Запуск двух асинхронных задач параллельно и сбор результатов в .NET 4.5
Я пытался какое-то время получить то, что, как я думал, будет просто работать с .NET 4.5
Я хочу одновременно выполнить две длительные задачи и собрать
приводит к лучшему способу C # 4.5 (RTM)
Следующие работы, но мне это не нравится, потому что:
- Каков правильный способ отмены асинхронной операции, которая не принимает CancellationToken?
- WaitAll vs WhenAll
- Секвенирование и реорганизация задач
- Запуск нескольких задач async и ожидание их завершения
- Очередь процесса с многопоточным или задачами
- Я хочу, чтобы
Sleep
был асинхронным методом, поэтому он можетawait
других методов - Он просто выглядит неуклюжим с
Task.Run()
- Я не думаю, что это даже использование каких-либо новых функций языка вообще!
Рабочий код:
public static void Go() { Console.WriteLine("Starting"); var task1 = Task.Run(() => Sleep(5000)); var task2 = Task.Run(() => Sleep(3000)); int totalSlept = task1.Result + task2.Result; Console.WriteLine("Slept for a total of " + totalSlept + " ms"); } private static int Sleep(int ms) { Console.WriteLine("Sleeping for " + ms); Thread.Sleep(ms); Console.WriteLine("Sleeping for " + ms + " FINISHED"); return ms; }
Нерабочий код:
Обновление: это действительно работает, и это правильный способ сделать это, единственной проблемой является Thread.Sleep
Этот код не работает, потому что вызов Sleep(5000)
немедленно запускает задание, поэтому Sleep(1000)
не запускается до его завершения. Это правда, даже если Sleep
async
и я не использую .Result
или вызов. Слишком рано.
Я подумал, что, возможно, есть способ получить незадействованную Task
, вызвав метод async
чтобы я мог затем вызвать Start()
для двух задач, но я не могу понять, как получить Task
от вызова метода async.
public static void Go() { Console.WriteLine("Starting"); var task1 = Sleep(5000); // blocks var task2 = Sleep(1000); int totalSlept = task1.Result + task2.Result; Console.WriteLine("Slept for " + totalSlept + " ms"); } private static async Task Sleep(int ms) { Console.WriteLine("Sleeping for " + ms); Thread.Sleep(ms); return ms; }
- Выполнение задачи в фоновом режиме в приложении WPF
- Вызов синхронного асинхронного метода
- Запуск задач в foreach Loop использует значение последнего элемента
- Почему это асинхронное действие зависает?
- Как ограничить количество одновременных операций асинхронного ввода-вывода?
- ConfigureAwait подталкивает продолжение в stream пула
- Шаблон для самоотдачи и перезапуска задачи
- Выполнение задач параллельно
Вы должны использовать Task.Delay вместо Sleep для асинхронного программирования, а затем использовать Task.WhenAll для объединения результатов задачи. Задачи будут выполняться параллельно.
public class Program { static void Main(string[] args) { Go(); } public static void Go() { GoAsync(); Console.ReadLine(); } public static async void GoAsync() { Console.WriteLine("Starting"); var task1 = Sleep(5000); var task2 = Sleep(3000); int[] result = await Task.WhenAll(task1, task2); Console.WriteLine("Slept for a total of " + result.Sum() + " ms"); } private async static Task Sleep(int ms) { Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount); await Task.Delay(ms); Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount); return ms; } }
async Task LongTask1() { ... } async Task LongTask2() { ... } ... { Task t1 = LongTask1(); Task t2 = LongTask2(); await Task.WhenAll(t1,t2); //now we have t1.Result and t2.Result }
Хотя ваш метод Sleep
asynchronous, Thread.Sleep
нет. Вся идея async заключается в повторном использовании одного streamа, а не для запуска нескольких streamов. Поскольку вы заблокировали использование синхронного вызова Thread.Sleep, это не сработает.
Я предполагаю, что Thread.Sleep
– это упрощение того, что вы на самом деле хотите сделать. Может ли ваша фактическая реализация кодироваться как асинхронные методы?
Если вам нужно запустить несколько синхронных блокирующих вызовов, посмотрите в другом месте, я думаю!
Сейчас выходные !
public static void Go() { Console.WriteLine("Start fosterage...\n"); var t1 = Sleep(5000, "Kevin"); var t2 = Sleep(3000, "Jerry"); var result = Task.WhenAll(t1, t2).Result; Console.WriteLine("\nMy precious spare time last for only {0}ms", result.Max()); Console.WriteLine("Press any key and take same beer..."); Console.ReadKey(); } private static async Task Sleep(int ms, string n) { Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); await Task.Delay(ms); Console.WriteLine("{0} waked up after {1}ms :(", n, ms); return ms; }
Обычная задача. Пример:
private static Task Sleep(int ms, string n) { return Task.Factory.StartNew(() => { Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); Thread.Sleep(ms); Console.WriteLine("{0} waked up after {1}ms :(", n, ms); return ms; }); }
Таинственный пример TaskCompletionSource :
private static Task Sleep(int ms, string n) { var tcs = new TaskCompletionSource (); Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); var t = Task.Factory.StartNew(() => { Thread.Sleep(ms); Console.WriteLine("{0} waked up after {1}ms :(", n, ms); tcs.SetResult(ms); }); return tcs.Task; }
Эта статья помогла объяснить многое. Это в стиле FAQ.
Часто задаваемые вопросы по Async / Await
В этой части объясняется, почему Thread.Sleep
работает в одном и том же исходном streamе, что приводит к моей первоначальной путанице.
Является ли ключевое слово «async» причиной вызова метода в очередь ThreadPool? Создать новый stream? Запустить ракетный корабль на Марс?
Нет. Нет. См. Предыдущие вопросы. Ключевое слово «async» указывает компилятору, что «ожидание» может использоваться внутри метода, так что метод может приостанавливаться в точке ожидания и возобновлять его выполнение асинхронно, когда ожидаемый экземпляр завершается. Вот почему компилятор выдает предупреждение, если нет «ожиданий» внутри метода, помеченного как «async».
Чтобы ответить на этот вопрос:
Я хочу, чтобы Sleep был асинхронным методом, поэтому он может ждать других методов
вы можете переписать функцию Sleep
следующим образом:
private static async Task Sleep(int ms) { Console.WriteLine("Sleeping for " + ms); var task = Task.Run(() => Thread.Sleep(ms)); await task; Console.WriteLine("Sleeping for " + ms + "END"); return ms; } static void Main(string[] args) { Console.WriteLine("Starting"); var task1 = Sleep(2000); var task2 = Sleep(1000); int totalSlept = task1.Result +task2.Result; Console.WriteLine("Slept for " + totalSlept + " ms"); Console.ReadKey(); }
запуск этого кода будет выводиться:
Starting Sleeping for 2000 Sleeping for 1000 *(one second later)* Sleeping for 1000END *(one second later)* Sleeping for 2000END Slept for 3000 ms