并行运行两个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)
不运行,直到它已完成。 这是真的,即使Sleep
是async
,我不使用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