并行运行两个asynchronous任务,并在.NET 4.5中收集结果

我一直在试图得到一些我认为会很简单的.NET 4.5的工作

我想同时解决两个长时间运行的任务并收集
导致最好的C#4.5(RTM)方式

下面的作品,但我不喜欢它,因为:

  • 我希望Sleep是一个asynchronous的方法,所以它可以await其他方法
  • 它看起来笨拙与Task.Run()
  • 我不认为这是甚至使用任何新的语言function!

工作代码:

 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)不运行,直到它已完成。 这是真的,即使Sleepasync ,我不使用await或调用。 .Result太快了。

我想也许有办法通过调用一个async方法来获得一个非运行的Task<T> ,所以我可以在这两个任务,然后调用Start() ,但我不知道如何得到一个Task<T>从调用一个asynchronous方法。

 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<int> Sleep(int ms) { Console.WriteLine("Sleeping for " + ms); Thread.Sleep(ms); return ms; } 

您应该使用Task.Delay而不是睡眠来进行asynchronous编程,然后使用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<int> 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不是。 asynchronous的整个想法是重用单个线程,而不是启动多个线程。 因为你已经阻止了对Thread.Sleep的同步调用,所以不能工作。

我假设Thread.Sleep是你真正想要做的简化。 你的实际实现可以编码为asynchronous方法吗?

如果你确实需要运行多个同步阻塞调用,看看我认为的其他地方!

这篇文章帮助解释了很多东西。 这是在常见问题的风格。

asynchronous/等待常见问题

这部分解释了为什么Thread.Sleep运行在相同的原始线程 – 导致我最初的困惑。

“async”关键字是否导致方法的调用排队到ThreadPool? 创build一个新的线程? 发射一艘火箭到火星?

不,不。 看到以前的问题。 “async”关键字指示编译器在方法内部可以使用“await”,这样该方法可以在等待的时间点暂停,并在等待的实例完成时asynchronous恢复执行。 这就是为什么如果在标记为“async”的方法中没有“awaits”,编译器会发出警告。

现在是周末了!

 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<int> 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; } 

普通的Task.Factory例子:

  private static Task<int> 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<int> Sleep(int ms, string n) { var tcs = new TaskCompletionSource<int>(); 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; } 

为了回答这个问题:

我希望睡眠是一个asynchronous的方法,所以它可以等待其他方法

你也许可以像这样重写Sleep函数:

 private static async Task<int> 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