C# tasks.ToList()是否创建包含新复制任务的列表,或者该列表引用相同的任务?
假设我们有一个任务数组(称为“任务”),然后将其转换为一个列表(称为“临时”),方法是:C# tasks.ToList()是否创建包含新复制任务的列表,或者该列表引用相同的任务?,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,假设我们有一个任务数组(称为“任务”),然后将其转换为一个列表(称为“临时”),方法是: var temp = tasks.ToList(); 数组元素指向的那些正在运行的任务会发生什么情况?我们是否有两组任务分别运行(一组在“任务”中,另一组在“临时”中)?或者他们指向相同的任务 以下代码(摘自考试参考文献70-483)与我所说的内容相关(最后三行): Task[]tasks=新任务[3]; tasks[0]=Task.Run(()=>{Thread.Sleep(2000);返回1;});
var temp = tasks.ToList();
数组元素指向的那些正在运行的任务会发生什么情况?我们是否有两组任务分别运行(一组在“任务”中,另一组在“临时”中)?或者他们指向相同的任务
以下代码(摘自考试参考文献70-483)与我所说的内容相关(最后三行):
Task[]tasks=新任务[3];
tasks[0]=Task.Run(()=>{Thread.Sleep(2000);返回1;});
tasks[1]=Task.Run(()=>{Thread.Sleep(1000);返回2;});
tasks[2]=Task.Run(()=>{Thread.Sleep(3000);返回3;});
而(tasks.Length>0){
int i=Task.WaitAny(任务);
Task completedTask=任务[i];
Console.WriteLine(completedTask.Result);
var temp=tasks.ToList();
移除温度(i);
tasks=临时ToArray();
}
更新:我知道最后三行的用途,但不知道它为什么起作用。
ToList
创建一个包含IEnumerable项的新列表。它不创建这些项的深度副本,只复制引用。因此,只有一组任务
这些行可能存在,因此开发人员可以使用RemoveAt
使用索引(从Task.WaitAny
返回的索引)轻松删除项目
[当我们调用一系列任务的ToList]时,会发生什么?我们是否有两组任务分别运行?或者他们指向相同的任务
这实际上是一个好问题,它取决于调用ToList
的源序列。如果temp
是一组正在运行的任务(如您的情况),那么ToList
只需创建它们引用的副本,这意味着您的新列表将指向同一组任务
但是,如果temp
构成了一系列尚未实例化的任务(由于延迟执行),那么每次调用ToList
时都会得到一组新的任务。下面是一个简单的示例(使用ToArray
,其效果与ToList
相同):
如果运行上面的代码,最终结果将是
20
,这意味着运行了两批任务(每个ToArray
调用一批)。但是,如果您取消对启用即时执行的行的注释,最终结果将变为10
,这表明后续的ToArray
调用仅复制引用,而不是生成新任务。MSDN说:“List.ToArray()将ArrayList的元素复制到新数组”(这属于最后一行代码).这意味着它复制了参考资料。在这种情况下,它不会创建新的项目和任务。列表和数组都包含相同的实际任务。我发现了一个非常相关的QA,它很好地解释了这一点:请将您的评论放入您的答案中,因为这是真实的答案。
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();
}
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);