【问题标题】:Run method async with cancel support使用取消支持运行异步方法
【发布时间】:2015-03-20 09:09:33
【问题描述】:

我必须从外部库中调用一个方法。我无法控制它,它会阻塞 UI 5 秒以上。这只是一种方法。因为我真的很喜欢 async/await,所以我的代码是这样的:

SoundSource = await Task.Run(() => CodecFactory.Instance.GetCodec(Path));

问题是它可以持续大约 30 秒并且用户想要取消它。我的第一个想法:在 GetAwaiter().OnCompleted 中设置一个 AutoResetEvent 并运行一个 while,它等待 AutoResetEvent 500 毫秒,然后检查布尔变量 _cancelLoading 是否为真:

            using (var waithandler = new AutoResetEvent(false))
            {
                var x = track.GetSoundSource();
                x.GetAwaiter().OnCompleted(() => { waithandler.Set(); });
                while (!x.IsCompleted)
                {
                    await Task.Run(() => waithandler.WaitOne(500));
                    if (_cancelLoading)
                    {
                        x.GetAwaiter().OnCompleted(() => x.Result.Dispose());
                        _isLoadingSoundSource = false;
                        _cancelLoading = false;
                        return;
                    }
                }
                _isLoadingSoundSource = false;
                SoundSource = x.Result;
            }

但这不是一个好的解决方案,因为它不知道是否可以将_isLoadingSoundSource 设置为true,因为新方法可能仍在运行该过程。可以使用另一个全局 AutoResetEvent 来修复它,但这确实很复杂,并且很容易以死板的形式结束。

是否有“取消”方法/任务的好方法(如果他们不支持,我不必使用任务)。我不需要中止它,如果它可以一直运行到结束,而不是仅仅处理结果,那就太好了。

【问题讨论】:

  • 您是否了解过 TPL 的取消支持?文档填充关于如何取消任务的信息。
  • 是的,当然,但这只有在您控制任务时才有效。
  • 如果该操作被构建为支持合作取消,它只能阻止该操作继续执行。在没有这种支持的情况下,您可以在操作实际完成之前将任务简单地标记为已完成,这正是您正在尝试做的事情,并且 TPL 肯定可以处理。

标签: c# async-await task cancellation


【解决方案1】:

如果您无法取消实际操作 (GetCodec),那么您所能做的就是在请求取消时忽略结果

private CancellationTokenSource _cts;
async Task SetSoundSourceAsync(string path)
{
  if (_cts != null)
    _cts.Cancel();
  _cts = new CancellationTokenSource();
  var token = _cts.Token;
  var result = await Task.Run(() => CodecFactory.Instance.GetCodec(path));
  if (token.IsCancellationRequested)
    return;
  SoundSource = result;
}

上面的示例代码假定它是从 UI 线程调用的。如果不是,_cts 将出现竞争条件。

【讨论】:

    猜你喜欢
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多