如何优雅地取消异步工作? [英] How to cancel async work gracefully?

查看:107
本文介绍了如何优雅地取消异步工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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.这是因为在关闭应用程序并以_fileNamenull的方式触发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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆