如何优雅地取消异步工作?

[英]How to cancel async work gracefully?


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:

我有一个UI应用程序,它每秒记录一些东西。每次触发OpenFileHandler时,我都必须开始记录到新文件。这是代码的一个非常简化的版本:

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!");
        }
    }
}

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是同步的,但在开始新的LogAsync任务之前,我需要确保挂起的WriteLineAsync已完成并且旧的日志文件已关闭。

I cannot do _task.Wait() inside OpenFileHandler because it will block the UI thread.

我不能在OpenFileHandler中执行_task.Wait(),因为它会阻止UI线程。

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.

我也无法使OpenFileHandler成为异步方法,并在其中等待_task。那是因为当应用程序关闭,并且在_fileName为null的情况下触发OpenFileHandler时,我想要“结束日志!”仍然在日志中的行。

How do I solve this?

我该如何解决这个问题?

2 个解决方案

#1


3  

As the first line of LogAsync, await the old task:

作为LogAsync的第一行,等待旧任务:

await prevTask;

You somehow need to pass in the previous task. Maybe as a method argument.

你不知何故需要传递上一个任务。也许作为方法论证。

You probably need to catch an OperationCancelledException, or:

您可能需要捕获OperationCancelledException,或者:

await prevTask.ContinueWith(_ => { }); //suppress exceptions

#2


0  

Could you not handle the special case of shutting the application down (and null being passed to the OpenFileHandler method)?

你能不能处理关闭应用程序的特殊情况(并将null传递给OpenFileHandler方法)?

So in the case of the application shutting down then you _cts.Cancel() and then _task.Wait() to allow the logs to complete being written.

因此,在应用程序关闭的情况下,然后使用_cts.Cancel()然后_task.Wait()以允许日志完成写入。

Rather than doing a while(true) can't you check if the CancellationToken has been cancelled or not, and if it has then exit and write the 'End of Log!'

你可以不检查CancellationToken是否已被取消,而不是做了一段时间(真实),如果已经取消,则退出并写下“结束日志!”


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2014/03/13/b086a91654bd02d02b06fb86ff6bee7a.html



 
  © 2014-2022 ITdaan.com 联系我们: