异步取消正在运行的操作

3

我正在进行一些关于.NET异步编程的测试,现在我卡在了尝试使用cancellationToken取消长时间操作上。

所以我有以下代码:

CancellationTokenSource cancelationToken = new CancellationTokenSource();

我的按钮来启动操作

    private void button2_Click(object sender, EventArgs e)
    {
        cancelationToken.Cancel(true);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        StartOperation(cancelationToken.Token);
    }

最后是我的操作。
    private async void StartOperation(CancellationToken cancelToken)
    {
        await GetItensFromDatabase2(cancelToken);
    }

    public static Task<int> GetItensFromDatabase(CancellationToken cancelToken)
    {
        //cancelToken.Register( () => Console.WriteLine("Canceled") );
        return Task.Factory.StartNew<int>(() =>
        {
            int result = 0;

            cancelToken.ThrowIfCancellationRequested();

            result = MyLongOperation();  // Simulates my operation -> I want to cancel while this operation is still running

            return result;

        }, cancelToken);
    }

那么,如何取消MyLongOperation()方法?有可能吗?

请在编写async代码时使用Task.Run而不是StartNew我在我的博客中解释了原因 - Stephen Cleary
Task.Run在.NET 4中不存在。 - mmarques
Microsoft.Bcl.Async 中,它是 TaskEx.Run - Stephen Cleary
2个回答

5
不可能在任何时候取消操作,CancellationToken 的目的是允许用户在长时间运行的操作期间取消操作...
while(!finished)
{
     cancelToken.ThrowIfCancellationRequested();
     //Some not cancelable operations
}

这里有一个更常见的可取消方法。
private static void LongRunning(CancellationToken cancelToken)
{
    while (true)
    {
        if(cancelToken.IsCancellationRequested)
        {
            return;
        }
        //Not canceled, continue to work
    }
}

用户请求取消,但只有执行者决定何时停止他的工作。通常执行者在达到某个"安全点"之后才会取消。

未经许可就中止长时间运行的操作不是好的体验,已经有很多帖子写过这个问题。


你的意思是我只能在循环内部取消操作吗? 如果我的当前执行点在 if(cancelToken.IsCancellationRequested) 的外部,而用户想要取消,那么此时不允许取消对吧? - mmarques
你可以线性地运行循环,执行一些代码,然后使用if(cancelToken.IsCancellationRequested) return;来检查是否取消,然后执行其他代码,再次检查是否取消... - Arsen Mkrtchyan

1
首先,如果您已经运行了逻辑并调用了“cancelToken.ThrowIfCancellationRequested”,然后取消操作,您将遇到一个问题。那么,“MyLongOperation”如何知道您已经取消了任务呢?:)
通常,取消长时间运行的任务需要将CancellationToken作为参数传入,因此代码看起来应该是这样的:
// Check if cancelled
// do work part 1
// Check if cancelled
// do work part 2

可取消操作的粒度由开发人员决定。

这就是我害怕的方法。谢谢。 - mmarques

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接