我偶然发现了Task.WhenAll的一个重载,即将 IEnumerable作为参数的重载
public static Task WhenAll(IEnumerable<Task<TResult>> tasks)
Run Code Online (Sandbox Code Playgroud)
我以为我会用以下短程序尝试这个功能.
在Test类中:
// contains the task numbers that has been run
private HashSet<int> completedTasks = new HashSet<int>();
// async function. waits a while and marks that it has been run:
async Task<int> Calculate(int taskNr)
{
string msg = completedTasks.Contains(taskNr) ?
"This task has been run before" :
"This is the first time this task runs";
Console.WriteLine($"Start task {i} {msg}");
await Task.Delay(TimeSpan.FromMilliseconds(100));
Console.WriteLine($"Finished task {taskNr}");
// mark that this task has been run:
completedTasks.Add(taskNr);
return i;
}
// async test function that uses Task.WhenAll(IEnumerable)
public async Task TestAsync()
{
Console.Write("Create the task enumerators... ");
IEnumerable<Task<int>> tasks = Enumerable.Range(1, 3)
.Select(i => Calculate(i));
Console.WriteLine("Done!");
Console.WriteLine("Start Tasks and await");
await Task.WhenAll(tasks);
Console.WriteLine("Finished waiting. Results:");
foreach (var task in tasks)
{
Console.WriteLine(task.Result);
}
}
Run Code Online (Sandbox Code Playgroud)
最后主要方案:
static void Main(string[] args)
{
var testClass = new TestClass();
Task t = Task.Run(() => testClass.TestAsync());
t.Wait();
}
Run Code Online (Sandbox Code Playgroud)
输出如下:
Create the task enumerators... Done!
Start Tasks and wait
Start task 1 This is the first time this task runs
Start task 2 This is the first time this task runs
Start task 3 This is the first time this task runs
Finished task 2
Finished task 3
Finished task 1
Finished waiting. Results:
Start task 1 This task has been run before
Finished task 1
1
Start task 2 This task has been run before
Finished task 2
2
Start task 3 This task has been run before
Finished task 3
3
Run Code Online (Sandbox Code Playgroud)
显然每个任务都运行两次!我究竟做错了什么?
更奇怪的是:如果我ToList()在Task.Whenall之前使用任务序列进行枚举,则该函数按预期工作!
Ren*_*ogt 12
您的问题是延迟执行.改变这一行
IEnumerable<Task<int>> tasks = Enumerable.Range(1, 3)
.Select(i => Calculate(i));
Run Code Online (Sandbox Code Playgroud)
至
var tasks = Enumerable.Range(1, 3)
.Select(i => Calculate(i)).ToList();
Run Code Online (Sandbox Code Playgroud)
Select()不立即执行 "查询",但返回枚举器.只有在使用此枚举器迭代任务时,才会为序列1 ... 3调用内部lambda.
在您的版本中,每次迭代时tasks,Calculate(i)都会再次调用并创建新任务.
与.ToList()执行枚举一次并且将所得的序列Task<int>被存储在List<Task<int>>(并且当该列表中列举的第二时间不再次生成).
当您调用Task.WhenAll(tasks)此方法时,迭代tasks并从而启动每个任务.当您稍后再次迭代(使用foreach循环输出结果)时,将再次执行查询,从而启动新任务.
| 归档时间: |
|
| 查看次数: |
494 次 |
| 最近记录: |