以下代码用于模拟耗时的工作。
async Task DoWork(string n)
{
for (var i = 1; i <= 5; i++)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine($"{n} runs {i} seconds. {DateTime.Now}");
}
}
async Task<int> F1()
{
await DoWork("f1");
return 1;
}
async Task<string> F2()
{
await DoWork("f2");
return "X";
}
以下代码将依次运行F1()
和F2()
。
async Task<string> Main()
{
var f1Task = F1();
var f2Task = F2();
var f1 = await f1Task;
var f2 = await f2Task;
return $"{f1} {f2}";
}
await Main();
以下代码可使它们并行运行。但是,它看起来很麻烦。
async Task<string> Main2()
{
int f1 = 0;
async Task G1() { f1 = await F1(); }
string f2 = "";
async Task G2() { f2 = await F2(); }
await Task.WhenAll(Task.Run(() => G1()), Task.Run(() => G2()));
return $"{f1} {f2}";
}
await Main2();
有没有一种方法可以不将它们包装在Task.Run()
中?
答案 0 :(得分:0)
您可以使用WhenAll()
方法使任务像
async Task<int> Main()
{
var f1Task = F1();
var f2Task = F2();
await Task.WhenAll(f1Task,f2Task);
return await f1Task + await f2Task;
}
答案 1 :(得分:0)
await本身不会启动异步操作。 用这样的任务开始DoWork:
async Task DoWork(string n)
{
await Task.Run(() => {
for (var i = 1; i <= 5; i++)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine($"{n} runs {i} seconds. {DateTime.Now}");
}
});
}
然后您可以执行以下操作:
{
var f1Task = F1();
var f2Task = F2();
return await f1Task + await f2Task;
}
答案 2 :(得分:0)
您说对了,看起来很麻烦。但是,它可以以一种简洁的方式完成。您可以创建一个任务数组,然后使用 WhenAll 一次等待所有任务。
var tasks = new List<Task<int>> { F1(), F2() };
var result = Task.WhenAll(tasks).GetAwaiter().GetResult();
唯一的条件是所有任务必须返回相同的结果类型。那么在这种情况下的结果是 int 的数组。
我写了一篇很好的关于并行处理的文章,您可以看看当任务是REST调用时如何完成此工作:http://www.michalbialecki.com/2018/04/19/how-to-send-many-requests-in-parallel-in-asp-net-core/
答案 3 :(得分:0)
这会增加io和CPU的负担。
如果只有I / O(即await Task.Delay
而不是Thread.Sleep
),则可以使用异步并发:
var task1 = F1();
var task2 = F2();
await Task.WhenAll(task1, task2);
int f1 = await task1;
string f2 = await task2;
但是,由于您也具有CPU(并且您的方法是同步的),因此您需要将其推送到另一个线程并使其并行。
有没有一种方法可以不将它们包装在Task.Run()中?
是的,但是Task.Run
是这里最简单的解决方案。它看起来不像您的示例那么麻烦:
var task1 = Task.Run(() => F1());
var task2 = Task.Run(() => F2());
await Task.WhenAll(task1, task2);
int f1 = await task1;
string f2 = await task2;
从技术上讲,Task.WhenAll
在这两个示例中都是可选的,但我喜欢它,因为它使语义更加清晰。