[英]Run two async tasks in parallel and collect results in .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
并且我没有使用await
或过早调用.Result
也是如此。
我想也许有一种方法可以通过调用async
方法来获得非运行的Task<T>
,这样我就可以在这两个任务上调用Start()
,但我不知道如何获得Task<T>
从调用异步方法。
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;
}
async Task<int> LongTask1() {
...
return 0;
}
async Task<int> LongTask2() {
...
return 1;
}
...
{
Task<int> t1 = LongTask1();
Task<int> t2 = LongTask2();
await Task.WhenAll(t1,t2);
//now we have t1.Result and t2.Result
}
您应该使用 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<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;
}
}
虽然您的Sleep
方法是异步的,但Thread.Sleep
不是。 异步的整个想法是重用单个线程,而不是启动多个线程。 因为您已经使用对 Thread.Sleep 的同步调用进行了阻塞,所以它不会起作用。
我假设Thread.Sleep
是您实际想要做的事情的简化。 您的实际实现可以编码为异步方法吗?
如果您确实需要运行多个同步阻塞调用,我认为请查看其他地方!
回答这个问题:
我希望 Sleep 是一个异步方法,以便它可以等待其他方法
您可以像这样重写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
现在是周末!
public async void Go()
{
Console.WriteLine("Start fosterage...");
var t1 = Sleep(5000, "Kevin");
var t2 = Sleep(3000, "Jerry");
var result = await Task.WhenAll(t1, t2);
Console.WriteLine($"My precious spare time last for only {result.Max()}ms");
Console.WriteLine("Press any key and take same beer...");
Console.ReadKey();
}
private static async Task<int> Sleep(int ms, string name)
{
Console.WriteLine($"{name} going to sleep for {ms}ms :)");
await Task.Delay(ms);
Console.WriteLine("${name} waked up after {ms}ms :(";
return ms;
}
这篇文章帮助解释了很多事情。 它是常见问题解答样式。
这部分解释了为什么Thread.Sleep
在同一个原始线程上运行 - 导致我最初的困惑。
“async”关键字是否会导致调用方法排队到线程池? 创建一个新线程? 向火星发射火箭飞船?
不。不。不。 请参阅前面的问题。 “async”关键字向编译器指示可以在方法内部使用“await”,这样方法可以在等待点挂起,并在等待的实例完成时异步恢复其执行。 这就是为什么如果标记为“async”的方法内部没有“await”,编译器会发出警告。
不幸的是,如果您的方法中还有另一个等待着您,Task.WhenAll()将无济于事。 异步方法不是并行的。
对于真正的并行执行,您应该手动启动新的任务,例如使用Task.Run()或ConfigureAwait(false)。
在此处查看详细信息: https : //www.wintellect.com/tasks-are-still-not-threads-and-async-is-not-parallel/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.