【问题标题】:Parallel start of several tasks, each of which has its own timeout并行启动多个任务,每个任务都有自己的超时时间
【发布时间】:2019-04-24 10:56:53
【问题描述】:

我有几个类似的任务,每个任务都限制为超时,即必须比指定时间更快地完成或返回空结果。这些任务的主要目的是接收来自服务器的具有超时限制的响应。 此类任务的示例如下:

       public async Task<List<Data>> GetDataWithTimeoutAsync(InputData data, int timeout)
        {   
            List<Data> resultData = new List<Data>;
            await Task.WhenAny(Task.Run(async () =>
                {
                    resultData.Add(SomeWork(data));
                }),
                Task.Delay(timeout));

            return resultData;
        }

这些任务中的每一个都可以单独正常工作。

但我想并行运行一些这样的任务。为此,我使用以下代码。

        public async Task<List<List<Data>>> GetAllDataAsync()
        {
            var resultTasks = new ConcurrentBag<Task<List<Data>>>();

            var firtsTask = GetDataWithTimeoutAsync(firstInputData, firtsTimeout);
            var secondTask = GetDataWithTimeoutAsync(secondInputData, secondTimeout);
            var thirdTask = GetDataWithTimeoutAsync(thirdInputData, thirdTimeout);

            resultTasks.Add(Task.Run(() => firtsTask));
            resultTasks.Add(Task.Run(() => secondTask));
            resultTasks.Add(Task.Run(() => thirdTask));

            await Task.WhenAll(resultTasks);

            var result = resultTasks.Select(t => t.Result).ToList();

            return result;

        }

但如果为嵌套任务设置了不同的超时时间,此代码将无法正常工作。在这种情况下,所有任务都会在最小的超时后完成。

如果每个任务都是 WhenAny 的结果,我如何与 WhenAll 并行运行一些任务?

【问题讨论】:

  • 您不应该在resultTasks.Add(Task.Run(() =&gt; firtsTask)); 执行Task.Run,​​因为您已经在GetDataWithTimeoutAsync 中启动了一个任务。就做resultTasks.Add(firtsTask));
  • @Peter Bons 我试图这样做。这没有导致结果。
  • @AndreyDengin 甚至没有必要为您创建答案:stackoverflow.com/questions/4238345/…
  • @AndreyDengin 也许可以选择使用CancellationTokenSource.CancelAfter,如果令牌没有被取消,则进行实际工作......

标签: c# task-parallel-library


【解决方案1】:

您的代码无法编译,所以我写了类似的东西。我无法重现你的结果。在我的情况下,具有不同超时的WhenAll 按预期工作。它在运行时间最长的任务完成时完成,即第二个(200 毫秒)。

public static async Task Main(string[] args)
{
    var task1 = GetDataAsync(100).WithTimeout(50);  // Should timeout after 50 msec
    var task2 = GetDataAsync(200).WithTimeout(300); // Should complete after 200 msec
    var task3 = GetDataAsync(300).WithTimeout(100); // Should timeout after 100 msec
    var stopwatch = Stopwatch.StartNew();
    var results = await Task.WhenAll(task1, task2, task3); // Wait for all
    stopwatch.Stop();
    Console.WriteLine($"Results: {String.Join(", ", results)}");
    Console.WriteLine($"Elapsed: {stopwatch.ElapsedMilliseconds} msec");
}

private static async Task<int> GetDataAsync(int input) // the input is used as delay
{
    await Task.Delay(input);
    return input;
}

public static Task<T> WithTimeout<T>(this Task<T> task, int timeout)
{
    var delayTask = Task.Delay(timeout).ContinueWith(_ => default(T),
        TaskContinuationOptions.ExecuteSynchronously);
    return Task.WhenAny(task, delayTask).Unwrap();
}

输出:

Results: 0, 200, 0
Elapsed: 211 msec

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 2018-04-28
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多