#c_sharp #net #многопоточность
Есть несколько объектов типа Task или Task. Необходимо дождаться завершения работы каждого из этих объектов и выполнить действия по завершению. Можно воспользоваться методом Task.Wait, например так: public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); t1.Wait(); t2.Wait(); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } Однако при большом количестве задач это будет выглядеть достаточно громоздко. Какие способы инфраструктура задач .NET предлагает для ожидания выполнения других задач?
Ответы
Ответ 1
Существует несколько способов решения предложенной задачи. Есть статический метод Task.WaitAll, который принимает в качестве аргументов массив задач и блокирует вызывающий поток до завершения всех этих задач. Кроме того, есть перегрузки этого метода, принимающие таймаут ожидания (и возвращающие признак, завершились ли задачи в указанное время) и/или токен отмены ожидания. Также есть перегрузка с параметром, принимающим переменное количество аргументов (ключевое слово params): public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); Task.WaitAll(t1, t2); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } Не надо путать метод Task.WaitAll с методом Task.WaitAny, ожидающим выполнения любой из переданных задач. Если есть возможность писать, используя .NET 4.5, то можно воспользоваться ключевыми словами async/await для асинхронного ожидания выполнения задач. Метод Task.WhenAll создаст задачу, которая завершится, когда завершатся все задачи, переданные ему в качестве аргументов. Код ниже будет выполняться синхронно, пока выполнение не дойдёт до инструкции await. В этот момент управление будет передано коду, вызвавшему метод Foo, а ожидание выполнения задач будет происходить в другом потоке. По завершению выполнения задач управление будет возвращено методу Foo и он продолжит работу: public static async void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); await Task.WhenAll(t1, t2); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } Кроме того, задача, порождаемая методом Task.WhenAll, является обычной задачей, а значит её можно синхронно подождать, используя метод Task.Wait: public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); Task.WhenAll(t1, t2).Wait(); Console.WriteLine("Tasks completed"); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } Ну и наконец, задачу порождённую методом Task.WhenAll можно продолжить, используя метод Task.ContinueWith. Этод метод запускает задачу, переданную ему в качестве аргумента, после завершения заданной задачи. В задаче-продолжении при это можно обработать результаты и исключения задач, которые изначально необходимо было подождать: public static void Foo() { var t1 = new Task(DoSomething1); var t2 = new Task(DoSomething2); t1.Start(); t2.Start(); var continuation = Task.WhenAll(t1, t2).ContinueWith( t => { Console.WriteLine("Tasks completed"); }); continuation.Wait(); } private static void DoSomething2() { Console.WriteLine("Do something 2"); } private static void DoSomething1() { Console.WriteLine("Do something 1"); } P.S. Отдельное спасибо @NickVolynkin за предложение задать вопрос и самому ответить на него и @PavelMayorov за идею с ожиданием через Task.WhenAll.
Комментариев нет:
Отправить комментарий