【发布时间】:2017-06-23 08:59:22
【问题描述】:
这是我想做的简化版:
private static int Inc(int input)
{
return input + 1;
}
private static async Task<int> IncAsync(int input)
{
await Task.Delay(200);
return input + 1;
}
private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(Func<TInput, TResult> func, IEnumerable<TInput> values)
{
var tasks = values.Select(value => Task.Run(() => func(value)))
.ToList();
await Task.WhenAll(tasks);
return tasks.Select(t => t.Result);
}
public async void TestAsyncStuff()
{
var numbers = new[] { 1, 2, 3, 4 };
var resultSync = await GetResultsAsync(Inc, numbers); // returns IEnumerable<int>
Console.WriteLine(string.Join(",", resultSync.Select(n => $"{n}")));
// The next line is the important one:
var resultAsync = await GetResultsAsync(IncAsync, numbers); // returns IEnumerable<Task<int>>
}
所以基本上,GetResultsAsync() 旨在成为一种通用方法,它将获取一组输入值的函数结果。在 TestAsyncStuff() 中,您可以看到调用同步函数 (Inc()) 的工作原理。
当我想调用一个异步函数(IncAsync())时,麻烦就来了。我得到的结果是IEnumerable<Task<int>> 类型。我可以对那个结果做一个Task.WhenAll(),这很有效:
var tasksAsync = (await GetResultsAsync(IncAsync, numbers)).ToList();
await Task.WhenAll(tasksAsync);
var resultAsync = tasksAsync.Select(t => t.Result);
Console.WriteLine(string.Join(",", resultAsync.Select(n => $"{n}")));
但我想收紧代码并执行await 内联。它应该看起来像这样:
var resultAsync = await GetResultsAsync(async n => await IncAsync(n), numbers);
但这也会返回一个IEnumerable<Task<int>>!我可以这样做:
var resultAsync = await GetResultsAsync(n => IncAsync(n).GetAwaiter().GetResult(), numbers);
这行得通...但据我所知,不鼓励使用Task.GetAwaiter().GetResult() 或Task.Result。
那么正确的做法是什么?
【问题讨论】:
-
var resultAsync = await GetResultsAsync(n => IncAsync(n).Result, numbers);? -
不要使用
async void,它只用于事件处理程序。你不能等待async void方法 -
还有
await Task.WhenAll(tasks); return tasks.Select(t => t.Result);?为什么?如果所有任务都有返回类型,WhenAll返回结果数组。通过清理代码,您应该能够编写int[] results=await Task.WhenAll(tasks); -
你到底想做什么?如果您最终致电
Task.Run,为什么不使用Parallel.For?Task.Run不会做任何异步操作,它会在后台运行作业 -
Parallel.For()是用于Actions,而不是Funcs?我会说 Plinq 是为Funcs
标签: c# asynchronous async-await task-parallel-library