tasks.ToList()是否创建包含新复制任务的列表,或列表是否指向相同的任务?

Kam*_*ely 2 .net c# task-parallel-library

假设我们有一系列任务(称为"任务"),然后将其转换为列表(称为"temp"),方法是:

var temp = tasks.ToList();
Run Code Online (Sandbox Code Playgroud)

运行数组元素指向的任务会发生什么?我们是否分别运行两组任务(一组在'tasks'中,另一组在'temp'中)?或者他们指向相同的任务?

以下代码(摘自考试参考文献70-483)与我所说的(最后三行)相关:

Task<int>[] tasks = new Task<int>[3];

tasks[0] = Task.Run(() => { Thread.Sleep(2000); return 1; });
tasks[1] = Task.Run(() => { Thread.Sleep(1000); return 2; });
tasks[2] = Task.Run(() => { Thread.Sleep(3000); return 3; });

while (tasks.Length > 0) {
    int i = Task.WaitAny(tasks);
    Task<int> completedTask = tasks[i];

    Console.WriteLine(completedTask.Result);

    var temp = tasks.ToList();
    temp.RemoveAt(i);
    tasks = temp.ToArray();
}
Run Code Online (Sandbox Code Playgroud)

更新:我知道最后三行的目的但不知道它为什么起作用.

Dou*_*las 8

当我们在一系列任务上调用ToList时会发生什么?我们是否分别运行两组任务?或者他们指向相同的任务?

这实际上是一个很好的问题,它取决于您调用的源序列ToList.如果temp是正在运行的任务的集合(如您的情况),则ToList只需创建其引用的副本,这意味着您的新列表将指向同一组任务.

但是,如果temp构成一系列尚未实例化的任务(由于延迟执行),那么每次调用时都会得到一组的任务ToList.这是一个简单的例子(使用ToArray,具有相同的效果ToList):

int count = 0;

var tasks = Enumerable.Range(0, 10).Select(_ => 
    Task.Run(() => Interlocked.Increment(ref count)));

// tasks = tasks.ToArray();   // deferred vs. eager execution

Task.WaitAll(tasks.ToArray());
Task.WaitAll(tasks.ToArray());

Console.WriteLine(count);
Run Code Online (Sandbox Code Playgroud)

如果运行上面的代码,最终结果将是20,这意味着运行了两批任务(每个ToArray调用一个).但是,如果取消注释启用执行执行的行,则最终结果将变为10,表示后续ToArray调用仅复制引用,而不是生成新任务.