【问题标题】:Async Task cancellation best practices: user versus program异步任务取消最佳实践:用户与程序
【发布时间】:2013-09-19 17:16:52
【问题描述】:

我正在开发一个库,该库在 UI 线程上执行一些懒惰的空闲后台工作(由于使用旧版 COM,它必须是这种方式)。消费应用可以通过取消令牌取消任务,也可以通过用户操作显式取消任务(通过IUserFeedback.Continue)。我正在尝试按照MSDN pattern 取消任务。

我的问题是,我是否应该像 IdleWorker1 那样区分用户取消(并返回 false)和调用应用程序(抛出)。或者我应该像IdleWorker2一样平等对待这两种情况并直接抛出?

我对界面设计者没有任何严格的要求(任务本质上是永无止境的,所以他们只关心到目前为止实际完成了多少工作,他们通过@987654326 接收进度@)。

简而言之,IdleWorker1

interface IUserFeedback
{
    bool Continue(int n);
}

class IdleWorker1
{
    public async Task<bool> DoIdleWorkAsync(CancellationToken ct, int timeSlice, IUserFeedback feedback)
    {
        bool more = true;
        int n = 0;
        while (more)
        {
            ct.ThrowIfCancellationRequested();
            more = feedback.Continue(++n);
            await Task.Delay(timeSlice);
        }
        return more;
    }
}

IdleWorker2

class IdleWorker2
{
    public async Task DoIdleWorkAsync(CancellationToken ct, int timeSlice, IUserFeedback feedback)
    {
        int n = 0;
        for (;;)
        {
            ct.ThrowIfCancellationRequested();
            if (!feedback.Continue(++n))
                throw new TaskCanceledException();
            await Task.Delay(timeSlice);
        }
    }
}

【问题讨论】:

    标签: c# .net task-parallel-library async-await


    【解决方案1】:

    我认为如果你不需要区分这两种类型的取消,被取消的方法甚至不应该知道是谁取消了它。

    为此,您需要一个CancellationTokenSource 供应用取消,另一个供用户取消。然后,您可以使用 CreateLinkedSource() 将它们组合成一个并将其令牌传递给方法。

    【讨论】:

    • 这太好了,我了解了CreateLinkedSource(),谢谢。但这需要我将新的“用户”取消令牌传递给IUserFeedback.Continue,对吗?我希望我能说服图书馆的消费者遵循这种模式。
    • 好吧,如果你想切换到这个,我想你不能再使用IUserFeedback.Continue了。这样,您会定期询问用户是否应该取消该方法。使用 CTS,用户必须告诉您何时应该取消该方法。
    • 我还是要汇报进度(而真正的进度不仅仅是计数)。另外,我在评论中说错了,将取消令牌传递给IUserFeedback.Continue 没有意义,它必须是取消源本身。但我确实喜欢这个主意,并会推荐给对方。
    猜你喜欢
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多