gpt4 book ai didi

c# - 任务.WhenAll(IEnumerable) : Tasks are started twice?

转载 作者:行者123 更新时间:2023-11-30 19:04:34 28 4
gpt4 key购买 nike

我刚刚偶然发现了 Task.WhenAll 的重载之一, 一个以 IEnumerable 作为参数的

public static Task WhenAll(IEnumerable<Task<TResult>> tasks)

我想我会用下面的短程序来尝试这个功能。

在测试类中:

// 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);
}
}

最后是主程序:

static void Main(string[] args)
{
var testClass = new TestClass();
Task t = Task.Run(() => testClass.TestAsync());
t.Wait();
}

输出如下:

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

显然每个任务运行两次!我做错了什么?

更奇怪的是:如果我在任务之前使用 ToList() 枚举任务序列。总之,该函数将按预期工作!

最佳答案

您的问题是延迟 执行。改变这一行

IEnumerable<Task<int>> tasks = Enumerable.Range(1, 3)
.Select(i => Calculate(i));

var tasks = Enumerable.Range(1, 3)
.Select(i => Calculate(i)).ToList();

Select()不会立即执行“查询”,而是返回一个枚举器。仅当您使用此枚举器遍历任务时,才会为序列 1...3 调用内部 lambda。
在您的版本中,每次迭代 tasks , Calculate(i)再次调用并创建新任务。
.ToList()枚举器执行一次,结果序列为 Task<int>存储在 List<Task<int>> 中(并且在第二次枚举该列表时不会再次生成)。


当您调用 Task.WhenAll(tasks) 时此方法遍历 tasks从而开始每个任务。当您稍后再次迭代时(使用 foreach 循环输出结果),查询将再次执行,从而启动新任务。

关于c# - 任务.WhenAll(IEnumerable) : Tasks are started twice?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45877209/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com