我必须从外部库调用一个方法。我无法控制它,它会阻止用户界面5秒+。这只是一种方法。因为我非常喜欢async / await,我的代码看起来像这样:
SoundSource = await Task.Run(() => CodecFactory.Instance.GetCodec(Path));
问题是它可以持续大约30秒,并且用户想要取消它。我的第一个想法:设置GetAwaiter().OnCompleted
一个AutoResetEvent并运行一个while
等待500秒的AutoResetEvent,然后检查,如果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修复,但这真的很复杂,最终可以很容易地结束。
是否有一种很好的方式来取消"方法/任务(如果他们不支持,我不必使用任务)。我不需要中止它,如果它可以运行直到它结束并且只是处理结果将会很好。
答案 0 :(得分:2)
如果您无法取消实际操作(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
会出现竞争条件。