【问题标题】:WhenAny behaving like WhenAll in certain case在某些情况下,WhenAny 的行为类似于 WhenAll
【发布时间】:2022-01-30 11:55:41
【问题描述】:

所以我遇到了第三方库的问题,即使在调用 cancellationToken.Cancel 时,调用也可能会卡住并且永远不会返回。下面是一个原型,它可以处理这种情况并且它可以工作。

public async Task MainAsync()
{
    try
    {
        await StartAsync().ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception thrown");
    }
}

private async Task<string> StartAsync()
{
    var cts = new CancellationTokenSource();

    cts.CancelAfter(3 * 1000);

    var tcs = new TaskCompletionSource<string>();

    cts.Token.Register(() => { Console.WriteLine("Cancelled"); tcs.TrySetCanceled(); });

    return await (await Task.WhenAny(tcs.Task, LongComputationAsync())
        .ConfigureAwait(false)).ConfigureAwait(false);
}

private async Task<string> LongComputationAsync()
{
    await Task.Delay(1 * 60 * 1000).ConfigureAwait(false);

    return "Done";
}

因此,Above 将等待 3 秒,它会抛出一个 TaskCancelledException 就像它应该的那样。 如果您随后将方法 LongComputationAsync 更改为以下内容:

private Task<string> LongComputationAsync()
{
    Task.Delay(1 * 60 * 1000).ConfigureAwait(false).GetAwaiter().GetResult();

    return Task.FromResult("Done");
}

我仍然希望它具有相同的行为,但它的作用是,它将等待整整 1 分钟(在 LongComputationAsync() 中指定)然后抛出 TaskCancelledException

谁能给我解释一下?关于这是如何工作的,或者这是否是开始时的正确行为。

【问题讨论】:

  • 嗯,当然可以。如果您阻塞调用线程,LongCompuationAsync 不是异步的,它会阻塞调用线程 1 分钟。当StartAsync 调用LongCompuationAsync 时,它会卡在那条线上,直到1 分钟过去它甚至都不会到达第一个await
  • 特别是对LongComputationAsync 的调用在您同步等待的1 分钟延迟之后才会返回,因此您基本上最终会调用WhenAny 来完成任务。

标签: c# async-await task-parallel-library .net-5


【解决方案1】:

谁能给我解释一下?

当然。该问题与WhenAny 无关。相反,问题在于代码假定方法在同步时是异步的。

这是一个相对容易犯的错误。但作为一般规则,具有异步签名的方法可能是异步的;它没有必须是异步的。

正如我在博客中所描述的,asynchronous methods begin executing synchronously, just like synchronous methods。只有当它们遇到await 时,它们才可能异步运行(即使那样,它们也可能会继续同步)。

所以,LongCompuationAsync 的新版本是同步的,它在将任务返回给StartAsync 之前执行整个方法,然后将其传递给WhenAny

【讨论】:

  • 我一直教导说,一旦您将函数声明为 Task,这意味着该函数将异步运行。只是出于好奇,有没有办法强制任务函数在不使用等待的情况下异步运行?
  • @Dethras:如果你的意思是强制它在线程池线程上运行,你可以使用Task.Run
猜你喜欢
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
  • 2020-12-09
相关资源
最近更新 更多