运行 方法异步取消支持
Run method async with cancel support
我必须从外部库调用一个方法。我无法控制它,它会阻止 UI 5 秒以上。这只是一种方法。因为我很喜欢async/await,所以我的代码是这样的:
SoundSource = await Task.Run(() => CodecFactory.Instance.GetCodec(Path));
问题是它可以持续大约 30 秒,用户想要取消它。我的第一个想法:在 GetAwaiter().OnCompleted
中设置一个 AutoResetEvent 并在 运行 中设置一个 while
,它等待 AutoResetEvent 500 毫秒,然后检查 bool 变量 _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 修复,但这真的很复杂,很容易以死的样子结束。
有什么好的方法可以 "cancel" method/Task(如果任务不支持,我就不必使用它)。我不需要中止它,如果它可以 运行 直到它结束而不只是处理结果就好了。
如果您无法取消实际操作(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
.
会出现竞争条件
我必须从外部库调用一个方法。我无法控制它,它会阻止 UI 5 秒以上。这只是一种方法。因为我很喜欢async/await,所以我的代码是这样的:
SoundSource = await Task.Run(() => CodecFactory.Instance.GetCodec(Path));
问题是它可以持续大约 30 秒,用户想要取消它。我的第一个想法:在 GetAwaiter().OnCompleted
中设置一个 AutoResetEvent 并在 运行 中设置一个 while
,它等待 AutoResetEvent 500 毫秒,然后检查 bool 变量 _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 修复,但这真的很复杂,很容易以死的样子结束。
有什么好的方法可以 "cancel" method/Task(如果任务不支持,我就不必使用它)。我不需要中止它,如果它可以 运行 直到它结束而不只是处理结果就好了。
如果您无法取消实际操作(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
.