如何优雅地取消异步工作? [英] How to cancel async work gracefully?
问题描述
我有一个UI应用程序,它每秒记录一次.每次触发OpenFileHandler
时,我都必须开始记录到新文件.这是代码的非常简化的版本:
I have a UI application which logs something every second. Every time OpenFileHandler
is fired, I must start logging to a new file. This is a very simplified version of the code:
string _logItem;
string _fileName;
CancellationTokenSource _cts;
Task _task;
private void OpenFileHandler(object sender, EventArgs e)
{
// once OpenFileHandler has been fired,
// the _logItem should go to the new file
if (_task != null && !_task.IsCompleted)
{
_cts.Cancel();
// can't do: _task.Wait();
}
if ( _fileName != null )
{
_cts = new CancellationTokenSource();
_task = LogAsync(_fileName, _cts.Token);
}
}
private async Task LogAsync(string fileName, CancellationToken ct)
{
using (var writer = new System.IO.StreamWriter(fileName, false))
{
try
{
while (true)
{
await Task.Delay(1000, ct);
await writer.WriteLineAsync(_logItem);
}
}
finally
{
writer.WriteLine("end of log!");
}
}
}
问题:OpenFileHandler
是同步的,但是在开始新的LogAsync
任务之前,我需要确保未完成的WriteLineAsync
已完成并且旧的日志文件已关闭.
The problem: OpenFileHandler
is synchronous, but I need to make sure the pending WriteLineAsync
has completed and the old log file has been closed, before I can start a new LogAsync
task.
我不能在OpenFileHandler
内部执行_task.Wait()
,因为它会阻塞UI线程.
I cannot do _task.Wait()
inside OpenFileHandler
because it will block the UI thread.
我也无法将OpenFileHandler
设为async
方法,并且无法在其中执行await _task
.这是因为在关闭应用程序并以_fileName
为null
的方式触发OpenFileHandler
时,我希望"end of log!"
行仍保留在日志中.
I also cannot make OpenFileHandler
an async
method and do await _task
inside it. That's because when the application is closed, and OpenFileHandler
is fired with _fileName
being null
, I want the "end of log!"
line to still be there in the log.
我该如何解决?
推荐答案
作为LogAsync
的第一行,等待旧任务:
As the first line of LogAsync
, await the old task:
await prevTask;
您需要以某种方式传递上一个任务.也许作为方法参数.
You somehow need to pass in the previous task. Maybe as a method argument.
您可能需要赶上OperationCancelledException
,或者:
You probably need to catch an OperationCancelledException
, or:
await prevTask.ContinueWith(_ => { }); //suppress exceptions
这篇关于如何优雅地取消异步工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!