Запуск двух асинхронных задач параллельно и сбор результатов в .NET 4.5

Я пытался какое-то время получить то, что, как я думал, будет просто работать с .NET 4.5

Я хочу одновременно выполнить две длительные задачи и собрать
приводит к лучшему способу C # 4.5 (RTM)

Следующие работы, но мне это не нравится, потому что:

  • Я хочу, чтобы 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; } 

Вы должны использовать 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 
  • В чем разница между возвратом пустоты и возвратом задачи?
  • Использовать Task.Run () в синхронном методе, чтобы избежать тупиковой остановки в асинхронном методе?
  • Отмена ожидающей задачи синхронно в streamе пользовательского интерфейса
  • Должны ли мы переключиться на использование асинхронного ввода-вывода по умолчанию?
  • Лучший способ конвертировать метод async на основе обратного вызова в ожидаемую задачу
  • Разница между TPL и async / await (Обработка streamов)
  • Когда использовать Task.Delay, когда использовать Thread.Sleep?
  • Давайте будем гением компьютера.