.Net使用Cancellation Framework取消并行任务

 更新时间:2022年06月17日 09:41:19   作者:天方  
这篇文章介绍了.Net使用Cancellation Framework取消并行任务的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

在.net 4.0中,引入了一个新的类CancellationToken,这个类基本上集成了我们各种常用的取消方式,在并发任务中非常有用。

同步模式下的取消:

一种比较常见的需要支持取消功能的的是一些比较耗时的分段操作:如视频转换,网络下载等,这种方式下的取消机制如下:

  • 建立一个标记位,表示该操作是否已经取消

  • UI线程在获取到取消事件后,置标记位为true

  • 耗时的操作线程里,没进行一小段操作之后查询该标记位,如果为true则主动退出。

使用方式如下:

    EventHandler externalEvent;
    void Example1()
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        externalEvent +=
         (sender, obj) => { cts.Cancel(); }; //wire up an external requester 
        try
        {
            int val = LongRunningFunc(cts.Token);
        }
        catch (OperationCanceledException)
        {
            //cleanup after cancellation if required... 
        }
    }

    private static int LongRunningFunc(CancellationToken token)
    {
        int total = 0;
        for (int i = 0; i < 1000; i++)
        {
            for (int j = 0; j < 1000; j++)
            {
                total++;
            }
            if (token.IsCancellationRequested)
            { // observe cancellation 
                throw new OperationCanceledException(token); // acknowledge cancellation 
            }
        }
        return total;
    }

异步模式下的取消

另外一种常见的方式是在一些异步操作中,往往不能主动释放,只能等待异步操作回调的时候才能操作结果。此时一般取消方法如下:

  • 任务线程注册异步操作完成的回调函数,开始异步操作。

  • UI线程接受取消指令,置取消标记位,并主动执行回调函数

  • 回调函数中通过取消标记位判断该任务是已经完成还是被取消的,并执行相关析构操作。

使用方式如下:

    void BlockingOperation(CancellationToken token)
    {
        ManualResetEvent mre = new ManualResetEvent(false);
        //register a callback that will set the MRE 
        CancellationTokenRegistration registration =
         token.Register(() => mre.Set());
        using (registration)
        {
            mre.WaitOne();
            if (token.IsCancellationRequested) //did cancellation wake us? 
                throw new OperationCanceledException(token);
        } //dispose the registration, which performs the deregisteration. 
    }

这里我们通过CancellationToken注册了一个回调方法以通知任务等待线程,也可以以我们经常使用的WaitHandle的那样的方式使用。

    void Wait(WaitHandle wh, CancellationToken token)
    {
        WaitHandle.WaitAny(new[] { wh, token.WaitHandle });
        if (token.IsCancellationRequested) //did cancellation wake us? 
            throw new OperationCanceledException(token);
    }

高级应用

由于例子比较简单,这里就只列举一下代码,不多介绍了。

一个CancellationToken对应多个任务

    void Example4()
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        Func1(cts.Token);
        Func2(cts.Token);
        Func3(cts.Token);
        //... 
        cts.Cancel(); // all listeners see the same cancellation request. 
    }

一个任务对应多个CancellationToken

    void LinkingExample(CancellationToken ct1, CancellationToken ct2)
    {
        CancellationTokenSource linkedCTS =
        CancellationTokenSource.CreateLinkedTokenSource(ct1, ct2);
        try
        {
            SlowFunc(linkedCTS.Token);
        }
        catch (OperationCanceledException oce)
        {
            if (ct1.IsCancellationRequested)
            {
                // ... 
            }
            else if (ct2.IsCancellationRequested)
            {
                // ... 
            }
        }
        linkedCTS.Dispose(); // clean up the linking. required. 
    }

最后我们再来一个并发查询时取消的例子:

    private void RunQuery()
    {
        int[] data = { 1, 2, 3 };
        CancellationTokenSource cts = new CancellationTokenSource();
        var query = data.AsParallel()
                     .WithCancellation(cts.Token) // token given to library code 
                     .Select((x) => SlowFunc(x, cts.Token)); // token passed to user code 
    }

    private int SlowFunc(int x, CancellationToken token) 
    { 
        int result 
        while(...) 
        { 
            if (token.IsCancellationRequested) 
            throw new OperationCanceledException(token); 
            ... 
        } 
        return result; 
    }

小结

.net 4.0中的Cancellation Framework还是非常实用的,通过它可以更有效的简化及规范的使用各种取消的操作方式,由于我也只会皮毛,在这里也只是介绍了它的基本用法,在后续的学习和应用中将继续进一步介绍。

到此这篇关于.Net使用Cancellation Framework取消并行任务的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解VS2012发布网站步骤

    详解VS2012发布网站步骤

    这篇文章主要以图文相结合的方式介绍了VS2012发布网站的详细步骤,需要了解的朋友可以参考下
    2015-08-08
  • ASP.NET中DataTable与DataSet之间的转换示例

    ASP.NET中DataTable与DataSet之间的转换示例

    如果你的数据不需要做关系映射,直接用DataTable效率比较高,下面有个不错的示例,感兴趣的朋友可以参考下
    2013-09-09
  • .Net Core创建Api进行文件上传功能

    .Net Core创建Api进行文件上传功能

    这篇文章主要介绍了.Net Core创建Api进行文件上传,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • ASP.NET对大文件上传的解决方案

    ASP.NET对大文件上传的解决方案

    在ASP.NET 开发的过程中,最大的问题就在于上传大文件时让开发者尤为的头疼,而且,上传时无法方便的做到多线程的操控和上传进度的显示。笔者在此给大家推荐一款简单易用的上传组件,从而快速便捷得解决了 ASP.NET 中的大文件上传问题
    2015-08-08
  • ASP.net中网站访问量统计方法代码

    ASP.net中网站访问量统计方法代码

    这篇文章介绍了ASP.net中网站访问量统计方法代码,有需要的朋友可以参考一下
    2013-11-11
  • Asp.net使用SignalR实现酷炫端对端聊天功能

    Asp.net使用SignalR实现酷炫端对端聊天功能

    这篇文章主要为大家详细介绍了Asp.net使用SignalR实现酷炫端对端聊天功能,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • 三种方法让Response.Redirect在新窗口打开

    三种方法让Response.Redirect在新窗口打开

    通过设置form的target属性同样可以让Response.Rederect所指向的url在新的窗口打开,下面为大家介绍三种具体的实现方法
    2013-10-10
  • 30 分钟掌握无刷新 Repeater

    30 分钟掌握无刷新 Repeater

    经过数个版本的迭代后, JQueryElement 3.3.0 版本中的 Repeater 基本上已经完善, 这里将分功能的总结讲解一下 Repeater 的使用方法
    2011-10-10
  • ASP.NET:设置页面buffer引出来的问题

    ASP.NET:设置页面buffer引出来的问题

    ASP.NET:设置页面buffer引出来的问题...
    2006-09-09
  • MVC页面之间参数传递解析

    MVC页面之间参数传递解析

    这篇文章主要为大家详细介绍了MVC页面之间参数传递方法,分享了MVC页面之间传值的两种方式,一是Html.RenderPartial方式,其次是Html.RenderAction 方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04

最新评论