Task.WaitAny当有多个任务同时完成时

时间:2017-05-31 22:23:18

标签: c# parallel-processing task

我正在使用Task.WaitAny并传入正在运行的任务数组。如果有多个任务同时完成,我想知道如何捕获所有已完成任务的索引。

例如,我正在检索完成的任务的索引,如下所示:`

int i = Task.WaitAny(taskArray);

使用索引i,我正在用另一个已启动的任务替换数组中的那个位置。 taskArray具有固定长度,我只能在完成时启动新任务并替换数组中的任务。如果我只在Task.WaitAny()上返回一个索引,我怎么能这样做,并且阵列中的多个任务可能同时完成。如果只返回一个索引,我该如何处理同时完成的其他任务?

`

2 个答案:

答案 0 :(得分:5)

  

如果只返回一个索引,我该如何处理同时完成的其他任务?

要明确:不可能出于所有意图和目的,确实不止一个任务可以同时完成 。即使同时在单独的CPU内核中运行,真正同时完成的可能性也基本为零。

所以,你真正要问的是一个任务完成的竞争条件,然后在你的线程中调用WaitAny()之前返回,并且调用方法中的后续代码可以执行,一个或多个其他任务也完成了。

您的问题缺乏有关实际情况的详细信息,但通常您有几个选择:

  1. 扫描您传递给taskArray的{​​{1}}以查找所有当前已完成的任务。
  2. 再次呼叫WaitAny(),除了您所知道的以外的所有任务。
  3. 哪个更合适取决于您实际需要对完成信息执行的操作。第一种选择最适用于您只关心当前完成的任务并希望立即处理它们的情况。第二种选择最适用于您对订购完成结果感兴趣的情况(即知道哪个任务以哪种顺序完成),但也希望立即继续等待剩余部分。

    请注意,在第二个选项中,如果在再次调用WaitAny()之前完成了多个任务,则由于竞争条件,排序有些随意。条件由WaitAny()方法“解决”,选择哪个任务作为刚刚完成的当前任务呈现给您。但除非你在每项任务中保留自己的时间信息,否则你将无法确定首先真正完成的是什么。

    如果上述内容未能充分解决您的问题,则需要改进您的问题,以便其中包含有关上述原因无法解决您的问题的详细信息,以及您如何尝试使用完成WaitAny()方法。请确保包含一个展示所有这一切的好Minimal, Complete, and Verifiable code example


    (旁白:以上所有当然都忽略了是否应该使用WaitAny()。通常最好使用WaitAny()异步等待。但相同的基本问题适用,并且不会改变答案,所以现在不要担心这种差异似乎是合理的。)

答案 1 :(得分:3)

任何任务都可以随时完成。当然,有可能同时完成两项以上的任务。

但在你的情况下,你不应该关心任何事情。 Task.WhenAny将返回已完成的数组中一个任务的索引。在索引处放置一个新任务并再次调用Task.WhenAny。如果数组中有任何已完成的任务,它将在没有延迟的情况下返回其中一个已完成任务的索引。

async Task Execute( IEnumerable<Func<Task>> taskFunctions, int maxParallel )
{
    var taskList = new List<Task>(maxParallel);
    foreach ( var taskFunc in taskFunctions )
    {
        var task = taskFunc();
        taskList.Add( task );
        if ( taskList.Count == maxParallel )
        {
            var idx = await Task.WhenAny( taskList ).ConfigureAwait(false);
            taskList.RemoveAt( idx );
        }
    }
    await Task.WhenAll( taskList ).ConfigureAwait(false);
}