澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:中档的二10拾二线程_职务

2019-05-05 作者:www.8455.com   |   浏览(66)

目录

复习:

 IO操作的MDA(Direct memory access)情势:直接待上访问内部存款和储蓄器,是一种不通过CPU而直接开始展览内部存款和储蓄器数据存款和储蓄的数据交流形式,大致能够不损耗CPU的财富;
 CL奥迪Q7所提供的异步编制程序模型便是丰盛利用硬件的DMA作用来刑释CPU的下压力;使用线程池进行田间管理,异步将专门的工作移交给线程池中的某些工作线程来成功,直到异步落成,异步才会透过回调的办法布告线程池,让CL汉兰达响应异步实现;

C#异步编制程序,

 IO操作的MDA(Direct memory access)格局:直接待上访问内部存款和储蓄器,是一种不经过CPU而一贯实行内部存款和储蓄器数据存款和储蓄的数据沟通形式,大约能够不损耗CPU的财富;
 CLPAJERO所提供的异步编制程序模型就是充足利用硬件的DMA功效来刑释CPU的压力;使用线程池举办管理,异步将专门的职业移交给线程池中的某些职业线程来成功,直到异步实现,异步才会由此回调的不二秘技公告线程池,让CL奇骏响应异步完结;

它是出新的一种样式,它利用 future 形式或回调(callback)机制,避防止生出不须求的线程。二个 future(或 promise)类型代表有些将在成功的操作。在 .NET 中,新版 future 类型有Task 和Task<TResult>。 

 IO操作的MDA(Direct memory access)形式:直接待上访问内部存款和储蓄器,是一种不经过CPU而直白开始展览内部存款和储蓄器数据存款和储蓄的数据调换格局,大约能够不损耗CPU的能源;
 CLLacrosse所提供的异步编制程序模型就是充裕利用硬件的DMA功能来释放CPU的压力;使用线程池实行田间管理,异步将工作移交给线程池中的有个别工作线程来产生,直到异步完毕,异步才会经过回调的法子通知线程池,让CL汉兰达响应异步落成;

  • 1.1 简介
  • 一.2创制职责
  • 壹.3使用任务实践基本的操作
  • 1.四组合任务
  • 一.五将APM格局转变为天职
  • 1.陆将EAP格局转变为天职
  • 一.七完毕裁撤选项
  • 1.八处理职务中的卓殊
  • 一.9互相运转职分
  • 一.十使用TaskScheduler配置职分施行
  • 参照书籍
  • 作者水平有限,假若不当接待各位商议指正!

其3章内容中大家关系了三种异步编制程序模型,这里差不离复习一下,分别如下

它是出现的1种样式,它采纳 future 形式或回调(callback)机制,以免止生出不要求的线程。一个 future(或 promise)类型代表有些快要实现的操作。在 .NET 中,新版 future 类型有Task 和Task<TResult>。 

异步编制程序形式------利用委托和线程池落成的情势

APM 异步编制程序模型,Asynchronous Programming Model            C#1.0

EAP 基于事件的异步编制程序方式,伊夫nt-based Asynchronous Pattern  C#2.0

TAP 基于职责的异步编程方式,Task-based Asynchronous 帕特tern    C#4.0

Asyncawait简化异步编程;任务并行库,Task Parallel Library     C#5

它是出现编制程序的壹种样式,选用 future 格局或回调(callback)机制,避防止生出不需要的线程。3个 future(或 promise)类型代表某些快要实现的操作。新版 future 类型有Task 和Task<TResult>。 老式异步编制程序 API 中,选择回调或事件(event) ,而不是future。


一.APM(异步编制程序方式):形如Beginxxx,Endxxx。

异步编制程序方式------采纳委托和线程池落成的情势

APM 异步编制程序模型,Asynchronous Programming Model            C#1.0

EAP 基于事件的异步编制程序形式,伊芙nt-based Asynchronous Pattern  C#2.0

TAP 基于职务的异步编制程序格局,Task-based Asynchronous Pattern    C#4.0

Asyncawait简化异步编制程序;职分并行库,Task Parallel Library     C#5

APM

         使用IAsyncResult设计情势的异步操作是经过名字为 BeginXXX 和 EndXXX 的多少个办法来实现,那两个办法分别指开端和竣事异步操作。该格局允许用更加少的CPU能源(线程)去做更加多的操作,.NET Framework好些个类也兑现了该格局,同时大家也能够自定义类来促成该格局(也正是在自定义的类中得以完结重临类型为IAsyncResult接口的BeginXXX方法和接受IAsyncResult包容类型作为唯壹参数的EndXXX方法),此外事委员会托项目也定义了BeginInvoke和EndInvoke方法。举例,FileStream类提供BeginRead和EndRead方法来从文件异步读取字节。那八个方法达成了 Read 方法的异步版本。

调用 BeginXXX 后,应用程序能够继续在调用线程上施行命令,同时异步操作在另一个线程上实行(要是有重回值还应调用 EndXXX终止异步操作,并向该格局传递BeginXXX 方法重回的IAsyncResult对象,收获操作的返回值)。

 澳门新萄京官方网站 1

CompletedSynchronously属性值侧重与提示音讯,而非操作

访问异步操作的结果,APM提供了多样方法:

一.在调用BeginXXX方法的线程上调用EndXXX方法来收获异步操作的结果;但是那种艺术会卡住调用线程,在领会操作完结未来调用线程才干继续运营。

二.循环查询IAsyncResult的IsComplete属性,操作完毕后再调用EndXXX方法来获得操作重回的结果。

叁.IAsyncResult的AsyncWaitHandle属性达成更为灵敏的等候逻辑,调用该属性WaitOne()方法来使二个线程阻塞并听候操作实现;再调用EndXXX方法来获得操作的结果。WaitHandle.WaitOne()可以钦定最长的等待时间,如超时重回false;

4. 在调用BeginXXX方法时提供AsyncCallback委托的实例作为参数,在异步操作落成后委托会自动调用(AsyncCallback对象)钦定的措施。(首推办法)AsyncCallback委托仅能够调用符合一定形式的法子(唯有一个参数IAsyncResult,且未有重返值);

澳门新萄京官方网站 2

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace AsyncCallbackDelegate
{
    public delegate int BinaryOp(int x, int y);
    class Program
    {
        private static bool isDone = false;
        static void Main(string[] args)
        {
            Console.WriteLine("*****  AsyncCallbackDelegate Example *****");
            Console.WriteLine("Main() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            BinaryOp b = new BinaryOp(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10,
              new AsyncCallback(AddComplete),
              "Main() thanks you for adding these numbers.");//传入数据
            // Assume other work is performed here...
            while (!isDone)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Working....");
            }
            Console.ReadLine();
        }

        #region Target for AsyncCallback delegate
        // Don't forget to add a 'using' directive for 
        // System.Runtime.Remoting.Messaging!
        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            //AsyncCallback委托的目标无法调用其他方法中创建的委托
            //IAsyncResult itfAR 实际上是System.Runtime.Remoting.Messaging命名空间AsyncResult类的一个实例
            AsyncResult ar = (AsyncResult)itfAR;
            //AsyncDelegate静态属性返回原始异步委托引用
            BinaryOp b = (BinaryOp)ar.AsyncDelegate;
            Console.WriteLine("10   10 is {0}.", b.EndInvoke(itfAR));

            // Retrieve the informational object and cast it to string.
            //AsyncState属性获取 BeginInvoke第四个参数传入的值
            string msg = (string)itfAR.AsyncState;
            Console.WriteLine(msg);
            isDone = true;
        }

        #endregion

        #region Target for BinaryOp delegate
        static int Add(int x, int y)
        {
            Console.WriteLine("Add() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(5000);
            return x   y;
        }
        #endregion
    }
}

AsyncCallback

不行捕获

在一道实践的不贰秘技里面普通管理非凡的方式是将也许抛出格外的代码放到try...catch...finally里面,之所以能够捕获到,是因为产生格外的代码与调用的代码位于同3个线程。当调用3个异步方法发生十分时,CL卡晚会捕获并且在EndXXX方法时再度将分外抛出抛出,所以异步调用中的十分在EndXXX方法出捕获就行了。

class ApmExceptionHandling 
{
   public static void Go() 
  {
      WebRequest webRequest = WebRequest.Create("http://0.0.0.0/");
      webRequest.BeginGetResponse(ProcessWebResponse, webRequest);
      Console.ReadLine();
   }
   private static void ProcessWebResponse(IAsyncResult result) {
      WebRequest webRequest = (WebRequest)result.AsyncState;

      WebResponse webResponse = null;
      try {
         webResponse = webRequest.EndGetResponse(result);
         Console.WriteLine("Content length: "   webResponse.ContentLength);
      }
      catch (WebException we) {
         Console.WriteLine(we.GetType()   ": "   we.Message);
      }
      finally {
         if (webResponse != null) webResponse.Close();
      }
   }
}

APM WinForm UI线程回调

由于AsyncCallback委托回调是从ThreadPool中的线程施行的,因而对此Winform,若是回调必要操作UI控件,就要求返回到UI线程去,常用的八个法子:

一.  Control类落成了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来支撑任何线程更新GUI分界面控件的体制(将回调方法投递到开创该控件的线程中实施)。

 澳门新萄京官方网站 3

Control类的 Invoke,BeginInvoke 内部贯彻如下:

a) Invoke(同步调用)先决断控件创造线程与目前线程是还是不是同样,同样则一贯调用委托方法;否则使用Win3二API的PostMessage异步奉行,但是Invoke内部会调用IAsyncResult.AsyncWaitHandle等待实施到位。

b) BeginInvoke(异步调用)使用Win3贰API的PostMessage 异步试行,并且重回IAsyncResult 对象。

利用方法:回调方法中对控件检查评定InvokeRequired值,if true,在该回调中封送3遍委托,调用控件的Invoke/ BeginInvoke方法;

 澳门新萄京官方网站 4

贰.GUI(WinForm/WPF)应用程序引进了1个线程管理模型:创设窗口的线程是有一无二能对尤其窗口进行立异的线程;在GUI线程中,平常必要扭转异步操作,使GUI线程不封堵并终止响应用户输入。但是,异步操作达成时,由于是用3个线程池线程实现的,而线程池线程不能更新UI控件。为化解那一个标题,FCL定义一个System.Threading.SynchronizationContext(线程同步上下文)的基类,其派生对象承担将3个应用程序模型连接到它的线程管理模型。

GUI线程都有一个和它涉及的SynchronizationContext派生对象,使用其静态Current属性获取:SynchronizationContext sc = SynchronizationContext.Current; 将此目的传给其余线程,当三个线程池线程要求让GUI线程更新UI时,调用该目的的sc.Post方法,向Post传递3个相称SendOrPostCallback委托签字的回调方法(一般是更新UI的操作方法,由GUI线程去试行),以及2个要传给回调方法的实参。

SynchronizationContext 的Post方法和Send方法的分别:(分别对应于异步/同步调用)

Post方法将回调方法送人GUI线程的队列,允许程序池线程立即返回,不进行阻塞;Post方法内部调用了BeginInvoke方法;

Send方法也将回调方法送人GUI线程的队列,但随后就会阻塞线程池线程,直到GUI线程完成对回调方法的调用。阻塞线程池线程极有可能造成线程池创建一个新的线程,避免调用该方法;Send方法内部调用了Invoke方法; 

对winform来讲是 System.Windows.Forms.WindowsFormsSynchronizationContext是其子类.

Winform窗口出现后,UI线程 SynchronizationContext.Current会被绑定赋值,唯有UI线程的Current不为null。

Public class SendOrPostUI {
   public static void Go() {
      System.Windows.Forms.Application.Run(new MyWindowsForm());
   }
   private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
      // Capture the calling thread's SynchronizationContext-derived object
      SynchronizationContext sc = SynchronizationContext.Current;
      // If there is no SC, just return what was passed in
      if (sc == null) return callback;
      // Return a delegate that, when invoked, posts to the captured SC a method that 
      // calls the original AsyncCallback passing it the IAsyncResult argument
      return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);
   }
   private sealed class MyWindowsForm : System.Windows.Forms.Form {
      public MyWindowsForm() {
         Text = "Click in the window to start a Web request";
         Width = 400; Height = 100;
      }
      protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
         // The GUI thread initiates the asynchronous Web request 
         Text = "Web request initiated";
         var webRequest = WebRequest.Create("http://Wintellect.com/");
         webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);
         base.OnMouseClick(e);
      }
      private void ProcessWebResponse(IAsyncResult result) {
         // If we get here, this must be the GUI thread, it's OK to update the UI
         var webRequest = (WebRequest)result.AsyncState;
         using (var webResponse = webRequest.EndGetResponse(result)) {
            Text = "Content length: "   webResponse.ContentLength;
         }
      }
   }
}

相比三种办法其实差不太多,二个是回调内重新卷入,二个是包裹原来的回调。然则SynchronizationContext业务层与UI分离来说的话是比较好;

异步编制程序的主旨惦记是异步操作:运维了的操作将会在1段时间后成功。那些操作正在施行时,不会卡住原来的线程。运营了那几个操作的线程,能够继续实施别的职务。当操作完结时,会打招呼它的 future,大概调用回调函数,以便让程序知道操作已经终止。

本体系首页链接:[C#十2线程编制程序类别(1)- 简单介绍 ]

2.EAP(基于事件的异步编制程序格局):那几个大家在.net中选择到了BackgroudWorker组件,使用办法是通过事件绑定管理的艺术。

APM

         使用IAsyncResult设计形式的异步操作是透过名字为 BeginXXX 和 EndXXX 的五个办法来促成,那多少个办法分别指初步和截止异步操作。该方式允许用更加少的CPU财富(线程)去做越多的操作,.NET Framework诸多类也落实了该形式,同时咱们也能够自定义类来得以完成该形式(也正是在自定义的类中得以完毕再次回到类型为IAsyncResult接口的BeginXXX方法和收受IAsyncResult包容类型作为唯壹参数的EndXXX方法),其它委托项目也定义了BeginInvoke和EndInvoke方法。比如,FileStream类提供BeginRead和EndRead方法来从文件异步读取字节。这七个方法落成了 Read 方法的异步版本。

调用 BeginXXX 后,应用程序能够继续在调用线程上进行命令,同时异步操作在另3个线程上实施(若是有重临值还应调用 EndXXX终止异步操作,并向该方法传递BeginXXX 方法再次来到的IAsyncResult对象,得到操作的返回值)。

 澳门新萄京官方网站 5

CompletedSynchronously属性值侧重与提醒新闻,而非操作

访问异步操作的结果,APM提供了三种办法:

壹.在调用BeginXXX方法的线程上调用EndXXX方法来收获异步操作的结果;但是那种措施会堵塞调用线程,在明白操作完结现在调用线程手艺持续运维。

贰.循环查询IAsyncResult的IsComplete属性,操作完毕后再调用EndXXX方法来收获操作再次来到的结果。

3.IAsyncResult的AsyncWaitHandle属性达成越来越灵活的守候逻辑,调用该属性WaitOne()方法来使2个线程阻塞并等候操作完毕;再调用EndXXX方法来取得操作的结果。WaitHandle.WaitOne()能够钦定最长的等候时间,如超时重回false;

四. 在调用BeginXXX方法时提供AsyncCallback委托的实例作为参数,在异步操作实现后委托会自动调用(AsyncCallback对象)钦命的艺术。(首荐办法)AsyncCallback委托仅可以调用符合一定格局的点子(唯有一个参数IAsyncResult,且从未再次回到值);

澳门新萄京官方网站 6澳门新萄京官方网站 7

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace AsyncCallbackDelegate
{
    public delegate int BinaryOp(int x, int y);
    class Program
    {
        private static bool isDone = false;
        static void Main(string[] args)
        {
            Console.WriteLine("*****  AsyncCallbackDelegate Example *****");
            Console.WriteLine("Main() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            BinaryOp b = new BinaryOp(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10,
              new AsyncCallback(AddComplete),
              "Main() thanks you for adding these numbers.");//传入数据
            // Assume other work is performed here...
            while (!isDone)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Working....");
            }
            Console.ReadLine();
        }

        #region Target for AsyncCallback delegate
        // Don't forget to add a 'using' directive for 
        // System.Runtime.Remoting.Messaging!
        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            //AsyncCallback委托的目标无法调用其他方法中创建的委托
            //IAsyncResult itfAR 实际上是System.Runtime.Remoting.Messaging命名空间AsyncResult类的一个实例
            AsyncResult ar = (AsyncResult)itfAR;
            //AsyncDelegate静态属性返回原始异步委托引用
            BinaryOp b = (BinaryOp)ar.AsyncDelegate;
            Console.WriteLine("10   10 is {0}.", b.EndInvoke(itfAR));

            // Retrieve the informational object and cast it to string.
            //AsyncState属性获取 BeginInvoke第四个参数传入的值
            string msg = (string)itfAR.AsyncState;
            Console.WriteLine(msg);
            isDone = true;
        }

        #endregion

        #region Target for BinaryOp delegate
        static int Add(int x, int y)
        {
            Console.WriteLine("Add() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(5000);
            return x   y;
        }
        #endregion
    }
}

AsyncCallback

那多少个捕获

在协同实行的格局里面普通管理至极的方法是将大概抛出十分的代码放到try...catch...finally里面,之所以能够捕获到,是因为爆发至极的代码与调用的代码位于同三个线程。当调用3个异步方法发生至极时,CLRAV四会捕获并且在EndXXX方法时再也将不胜抛出抛出,所以异步调用中的万分在EndXXX方法出捕获就行了。

class ApmExceptionHandling 
{
   public static void Go() 
  {
      WebRequest webRequest = WebRequest.Create("http://0.0.0.0/");
      webRequest.BeginGetResponse(ProcessWebResponse, webRequest);
      Console.ReadLine();
   }
   private static void ProcessWebResponse(IAsyncResult result) {
      WebRequest webRequest = (WebRequest)result.AsyncState;

      WebResponse webResponse = null;
      try {
         webResponse = webRequest.EndGetResponse(result);
         Console.WriteLine("Content length: "   webResponse.ContentLength);
      }
      catch (WebException we) {
         Console.WriteLine(we.GetType()   ": "   we.Message);
      }
      finally {
         if (webResponse != null) webResponse.Close();
      }
   }
}

APM WinForm UI线程回调

由于AsyncCallback委托回调是从ThreadPool中的线程实践的,由此对此Winform,若是回调须要操作UI控件,就供给再次来到到UI线程去,常用的五个情势:

一.  Control类达成了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来支撑任何线程更新GUI分界面控件的机制(将回调方法投递到创设该控件的线程中实行)。

 澳门新萄京官方网站 8

Control类的 Invoke,BeginInvoke 内部贯彻如下:

a) Invoke(同步调用)先判别控件创立线程与近期线程是还是不是一样,一样则向来调用委托方法;否则使用Win3二API的PostMessage异步实行,不过Invoke内部会调用IAsyncResult.AsyncWaitHandle等待试行到位。

b) BeginInvoke(异步调用)使用Win3贰API的PostMessage 异步实践,并且返回IAsyncResult 对象。

动用格局:回调方法中对控件检查测试InvokeRequired值,if true,在该回调中封送1次委托,调用控件的Invoke/ BeginInvoke方法;

 澳门新萄京官方网站 9

二.GUI(WinForm/WPF)应用程序引进了3个线程管理模型:创立窗口的线程是并世无双能对越发窗口进行创新的线程;在GUI线程中,日常须要扭转异步操作,使GUI线程不封堵并终止响应用户输入。可是,异步操作完毕时,由于是用3个线程池线程完结的,而线程池线程不可能更新UI控件。为解决这个主题材料,FCL定义一个System.Threading.SynchronizationContext(线程同步上下文)的基类,其派生对象承担将3个应用程序模型连接到它的线程管理模型。

GUI线程都有二个和它涉及的SynchronizationContext派生对象,使用其静态Current属性获取:SynchronizationContext sc = SynchronizationContext.Current; 将此目的传给其余线程,当2个线程池线程须要让GUI线程更新UI时,调用该目的的sc.Post方法,向Post传递七个相称SendOrPostCallback委托具名的回调方法(一般是更新UI的操作方法,由GUI线程去施行),以及四个要传给回调方法的实参。

SynchronizationContext 的Post方法和Send方法的区分:(分别对应于异步/同步调用)

Post方法将回调方法送人GUI线程的队列,允许程序池线程立即返回,不进行阻塞;Post方法内部调用了BeginInvoke方法;

Send方法也将回调方法送人GUI线程的队列,但随后就会阻塞线程池线程,直到GUI线程完成对回调方法的调用。阻塞线程池线程极有可能造成线程池创建一个新的线程,避免调用该方法;Send方法内部调用了Invoke方法; 

对winform来讲是 System.Windows.Forms.WindowsFormsSynchronizationContext是其子类.

Winform窗口现身后,UI线程 SynchronizationContext.Current会被绑定赋值,唯有UI线程的Current不为null。

Public class SendOrPostUI {
   public static void Go() {
      System.Windows.Forms.Application.Run(new MyWindowsForm());
   }
   private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
      // Capture the calling thread's SynchronizationContext-derived object
      SynchronizationContext sc = SynchronizationContext.Current;
      // If there is no SC, just return what was passed in
      if (sc == null) return callback;
      // Return a delegate that, when invoked, posts to the captured SC a method that 
      // calls the original AsyncCallback passing it the IAsyncResult argument
      return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);
   }
   private sealed class MyWindowsForm : System.Windows.Forms.Form {
      public MyWindowsForm() {
         Text = "Click in the window to start a Web request";
         Width = 400; Height = 100;
      }
      protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
         // The GUI thread initiates the asynchronous Web request 
         Text = "Web request initiated";
         var webRequest = WebRequest.Create("http://Wintellect.com/");
         webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);
         base.OnMouseClick(e);
      }
      private void ProcessWebResponse(IAsyncResult result) {
         // If we get here, this must be the GUI thread, it's OK to update the UI
         var webRequest = (WebRequest)result.AsyncState;
         using (var webResponse = webRequest.EndGetResponse(result)) {
            Text = "Content length: "   webResponse.ContentLength;
         }
      }
   }
}

相比较二种艺术其实差不太多,四个是回调内再也卷入,二个是包裹原来的回调。不过SynchronizationContext业务层与UI分离来说的话是相比好;

EAP

EAP是为了更便于处理UI的更新推出的模式,主要优点:它同Visual Studio UI设计器进行了很好的集成,可将大多数实现了EAP的类拖放到设计平面(design surface)上,双击控件对应的XXXCompleted事件名,会自动生成事件的回调方法,并将方法同事件自身联系起来。EAP保证事件在应用程序的GUI线程上引发,允许事件回调方法中的代码更新UI控件;

EAP另一重要功能:支持EAP的类自动将应用程序模型映射到它的线程处理模型;EAP类在内部使用SynchronizationContext类。有的EAP类提供了取消、进度报告功能。

   FCL中只有一八个项目完毕了EAP形式,一般有1个XXXAsync方法和贰个对应的XXXCompleted事件,以及这一个措施的同台版本:

*       System.Object的派生类型:*

*                  System.Activies.WorkflowInvoke  *

*                  System.Deployment.Application.ApplicationDeployment*

*                  System.Deployment.Application.InPlaceHosingManager*

*                  System.Net.Mail.SmtpClient*

*                  System.Net.PeerToPeer.PeerNameResolver*

*                  System.Net.PeerToPeer.Collaboration.ContactManager*

*                  System.Net.PeerToPeer.Collaboration.Peer*

*                  System.Net.PeerToPeer.Collaboration.PeerContact*

*                  System.Net.PeerToPeer.Collaboration.PeerNearMe*

*                  System.ServiceModel.Activities.WorkflowControlClient*

*                  System.ServiceModel.Discovery.AnnoucementClient*

*                  System.ServiceModel.Discovery.DiscoveryClient*

*      System.ComponentModel.Component的派生类型:*

                  System.ComponentModel.BackgroundWorker

                  System.Media.SoundPlay

                  System.Net.WebClient

                  System.Net.NetworkInformation.Ping

                  System.Windows.Forms.Picture博克斯(承袭于Control类,Control类派生于Component类)

private sealed class MyForm : System.Windows.Forms.Form {
    protected override void OnClick(EventArgs e) {
      // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
      WebClient wc = new WebClient();
      // When a string completes downloading, the WebClient object raises the 
      // DownloadStringCompleted event which will invoke our ProcessString method         
      wc.DownloadStringCompleted  = ProcessString;
      // Start the asynchronous operation (this is like calling a BeginXxx method)
      wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
      base.OnClick(e);
    }
    // This method is guaranteed to be called via the GUI thread
    private void ProcessString(Object sender, DownloadStringCompletedEventArgs e) {
      // If an error occurred, display it; else display the downloaded string
      System.Windows.Forms.MessageBox.Show((e.Error != null) ? e.Error.Message : e.Result);
      }
   }

BackgroundWorker:唯有该类型用于可用来实行异步的图谋范围的干活;提供多个事件:

DoWork:向这么些事件登记的办法应该包涵总括范围的代码。这几个事件由一个线程池线程调用RunWorkerAsync(多个重载方法,带参的法门是向DoWork登记的诀窍的DoWork伊夫ntArgs参数对象的Argument属性传值,只可以在登记的章程中(如e.Argument)获取,Result属性必须设置成计算范围的操作希望重回的值)时引发;

ProgressChanged:向那一个事件登记的办法应该包蕴使用进程音信来更新UI的代码。这些事件接贰连三在GUI线程上引发。DoWork登记的法门必须定时调用BackgroundWorker的ReportProgress方法来诱惑ProgressChanged事件;

RunWorkerCompleted:向那么些事件登记的方法应该包涵使用总计范围操作的结果对UI进行翻新的代码。这些事件接2连3在GUI线程上引发。Result获取表示异步操作的结果;

集体属性:CancellationPending(标志是不是已呼吁撤除后台操作)、IsBusy(标记是不是正在运营异步操作)、WorkReportsProgress(获取/设置是不是报告进度更新)、WorkerSupportsCancellation(获取/设置是或不是扶助异步撤废)

公物艺术:CancelAsync(请求撤销挂起的后台操作)、ReportProgress、RunWorkerAsync

异常

十三分不会抛出。在XXXCompleted事件管理方法中,必须询问AsyncCompleted伊夫ntArgs的Exception属性,看它是否null。假诺不是null,就务须利用if语句判定Exception派生对象的门类,而不是应用catch块。

异步编制程序格局------选择委托和线程池落成的情势

APM 异步编制程序模型,Asynchronous Programming Model            C#1.0

EAP 基于事件的异步编制程序情势,伊夫nt-based Asynchronous Pattern  C#2.0

TAP 基于职分的异步编制程序格局,Task-based Asynchronous Pattern    C#4.0

Asyncawait简化异步编制程序;职务并行库,Task Parallel Library     C#5


三.TPL(基于任务的异步编制程序格局):那个就能够用到任务并行库。

EAP

EAP是为了更便于处理UI的更新推出的模式,主要优点:它同Visual Studio UI设计器进行了很好的集成,可将大多数实现了EAP的类拖放到设计平面(design surface)上,双击控件对应的XXXCompleted事件名,会自动生成事件的回调方法,并将方法同事件自身联系起来。EAP保证事件在应用程序的GUI线程上引发,允许事件回调方法中的代码更新UI控件;

EAP另一重要功能:支持EAP的类自动将应用程序模型映射到它的线程处理模型;EAP类在内部使用SynchronizationContext类。有的EAP类提供了取消、进度报告功能。

   FCL中唯有二十一个种类落成了EAP情势,一般有三个XXXAsync方法和四个对应的XXXCompleted事件,以及这个措施的一路版本:

*       System.Object的派生类型:*

*                  System.Activies.WorkflowInvoke  *

*                  System.Deployment.Application.ApplicationDeployment*

*                  System.Deployment.Application.InPlaceHosingManager*

*                  System.Net.Mail.SmtpClient*

*                  System.Net.PeerToPeer.PeerNameResolver*

*                  System.Net.PeerToPeer.Collaboration.ContactManager*

*                  System.Net.PeerToPeer.Collaboration.Peer*

*                  System.Net.PeerToPeer.Collaboration.PeerContact*

*                  System.Net.PeerToPeer.Collaboration.PeerNearMe*

*                  System.ServiceModel.Activities.WorkflowControlClient*

*                  System.ServiceModel.Discovery.AnnoucementClient*

*                  System.ServiceModel.Discovery.DiscoveryClient*

*      System.ComponentModel.Component的派生类型:*

                  System.ComponentModel.BackgroundWorker

                  System.Media.SoundPlay

                  System.Net.WebClient

                  System.Net.NetworkInformation.Ping

                  System.Windows.Forms.PictureBox(承袭于Control类,Control类派生于Component类)

private sealed class MyForm : System.Windows.Forms.Form {
    protected override void OnClick(EventArgs e) {
      // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
      WebClient wc = new WebClient();
      // When a string completes downloading, the WebClient object raises the 
      // DownloadStringCompleted event which will invoke our ProcessString method         
      wc.DownloadStringCompleted  = ProcessString;
      // Start the asynchronous operation (this is like calling a BeginXxx method)
      wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
      base.OnClick(e);
    }
    // This method is guaranteed to be called via the GUI thread
    private void ProcessString(Object sender, DownloadStringCompletedEventArgs e) {
      // If an error occurred, display it; else display the downloaded string
      System.Windows.Forms.MessageBox.Show((e.Error != null) ? e.Error.Message : e.Result);
      }
   }

BackgroundWorker:只有该类型用于可用来推行异步的妄想范围的劳作;提供多个事件:

DoWork:向那些事件登记的不2法门应该包含总结范围的代码。这几个事件由三个线程池线程调用RunWorkerAsync(多个重载方法,带参的法子是向DoWork登记的法子的DoWork伊芙ntArgs参数对象的Argument属性传值,只可以在登记的办法中(如e.Argument)获取,Result属性必须设置成总计范围的操作希望重返的值)时引发;

ProgressChanged:向那些事件登记的不二等秘书籍应该包罗使用进程新闻来更新UI的代码。那个事件接贰连叁在GUI线程上引发。DoWork登记的方法必须定期调用BackgroundWorker的ReportProgress方法来诱惑ProgressChanged事件;

RunWorkerCompleted:向那个事件登记的章程应该包括使用总计范围操作的结果对UI进行翻新的代码。这一个事件接二连叁在GUI线程上引发。Result获取表示异步操作的结果;

公共属性:CancellationPending(标志是或不是已呼吁裁撤后台操作)、IsBusy(标志是或不是正在运维异步操作)、WorkReportsProgress(获取/设置是或不是报告进度更新)、WorkerSupportsCancellation(获取/设置是不是接济异步撤废)

公家措施:CancelAsync(请求撤废挂起的后台操作)、ReportProgress、RunWorkerAsync

异常

那些不会抛出。在XXXCompleted事件管理方法中,必须询问AsyncCompleted伊夫ntArgs的Exception属性,看它是还是不是null。若是或不是null,就亟须采用if语句判别Exception派生对象的花色,而不是使用catch块。

TAP

.NET四.0 中引进了新的异步编制程序模型“基于职分的异步编制程序模型(TAP)”,并且推荐大家在开采新的拾贰线程应用程序中首选TAP,在.NET四.5中更为对TPL库进行了大气的优化与改善(async和await)。那未来本人先介绍下TAP具备怎么样优势:

        三.  轻易达成职务等待、任务撤消、一而再任务、相当管理(System.AggregateException)、GUI线程操作。

       4.  在职责运维后,可以每十二日以职分延续的样式登记回调。

       5.  丰硕利用现存的线程,幸免创设不要求的额外线程。

       6.  结合C#五.0引进async和await关键字轻便完结“异步方法”。

APM转换为TAP:

选拔TaskFactory的FromAsync方法,传递多少个实参:BeginXxx方法、EndXxx方法、Object状态、可选的TaskCreationOptions值,再次来到对1个Task对象的引用;

private static void ConvertingApmToTask() {
      // Instead of this:
      WebRequest webRequest = WebRequest.Create("http://Wintellect.com/");
      webRequest.BeginGetResponse(result => {
         WebResponse webResponse = null;
         try {
            webResponse = webRequest.EndGetResponse(result);
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (WebException we) {
            Console.WriteLine("Failed: "   we.GetBaseException().Message);
         }
         finally {
            if (webResponse != null) webResponse.Close();
         }
      }, null);
      Console.ReadLine();  // for testing purposes
      // Make a Task from an async operation that FromAsync starts
      webRequest = WebRequest.Create("http://Wintellect.com/");
      var t1 = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse, null, TaskCreationOptions.None);
      var t2 = t1.ContinueWith(task => {
         WebResponse webResponse = null;
         try {
            webResponse = task.Result;
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (AggregateException ae) {
            if (ae.GetBaseException() is WebException)
               Console.WriteLine("Failed: "   ae.GetBaseException().Message);
            else throw;
         }
         finally { if (webResponse != null) webResponse.Close(); }
      });
      try {t2.Wait();  // for testing purposes only}
      catch (AggregateException) { }
   }

EAP转换成TAP:

使用System.Threading.Tasks.TaskCompletionSource类举办李包裹装;

澳门新萄京官方网站 10

当协会贰个TaskCompletionSource对象,也会变动贰个Task,可经过其Task属性获取;当1个异步操作达成时,它应用TaskCompletionSource对象来设置它因为何而产生,撤除,未管理的13分或许它的结果。调用某些SetXxx方法,能够安装底层Task对象的情况。

private sealed class MyFormTask : System.Windows.Forms.Form {
      protected override void OnClick(EventArgs e) {
         // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
         WebClient wc = new WebClient();
         // Create the TaskCompletionSource and its underlying Task object
         var tcs = new TaskCompletionSource<String>();
         // When a string completes downloading, the WebClient object raises the 
         // DownloadStringCompleted event which will invoke our ProcessString method
         wc.DownloadStringCompleted  = (sender, ea) => {
            // This code always executes on the GUI thread; set the Task’s state
            if (ea.Cancelled) tcs.SetCanceled();
            else if (ea.Error != null) tcs.SetException(ea.Error);
            else tcs.SetResult(ea.Result);
         };
         // Have the Task continue with this Task that shows the result in a message box
// NOTE: The TaskContinuationOptions.ExecuteSynchronously flag is required to have this code
         // run on the GUI thread; without the flag, the code runs on a thread pool thread 
         tcs.Task.ContinueWith(t => {
            try { System.Windows.Forms.MessageBox.Show(t.Result);}
            catch (AggregateException ae) {
               System.Windows.Forms.MessageBox.Show(ae.GetBaseException().Message);
            }
         }, TaskContinuationOptions.ExecuteSynchronously);
         // Start the asynchronous operation (this is like calling a BeginXxx method)
         wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
         base.OnClick(e);
      }
   }

实现了TAP的类:存在XxxTaskAsync的方法, 援救异步操作的撤除和速度的告知的作用;

裁撤:能够通过同盟式撤消情势,向异步方法传入CancellationToken 参数,通过调用其ThrowIfCancellationRequested方法来定期检查操作是或不是曾经撤回;

进程报告:能够因而IProgress<T>接口来促成速度报告的成效;

更新GUI: TaskScheduler.FromCurrentSynchronizationContext()获取同步上下文职分调治器,将关联该目标的全数职分都调节给GUI线程,使任务代码能成功更新UI;

private sealed class MyForm : System.Windows.Forms.Form {
        public MyForm() {
            Text = "Synchronization Context Task Scheduler Demo";
            Visible = true; Width = 400; Height = 100;
        }
         private static Int32 Sum(CancellationToken ct, Int32 n) {
        Int32 sum = 0;
        for (; n > 0; n--) {
            // The following line throws OperationCanceledException when Cancel 
            // is called on the CancellationTokenSource referred to by the token
            ct.ThrowIfCancellationRequested();
            //Thread.Sleep(0);   // Simulate taking a long time
            checked { sum  = n; }
        }
        return sum;
       }
        private readonly TaskScheduler m_syncContextTaskScheduler =
           TaskScheduler.FromCurrentSynchronizationContext();
        private CancellationTokenSource m_cts;
        protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
            if (m_cts != null) {    // An operation is in flight, cancel it
                m_cts.Cancel();
                m_cts = null;
            } else {                // An operation is not in flight, start it
                Text = "Operation running";
                m_cts = new CancellationTokenSource();
           // This task uses the default task scheduler and executes on a thread pool thread
                var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token);
                t.Start();
 // These tasks use the synchronization context task scheduler and execute on the GUI thread
                t.ContinueWith(task => Text = "Result: "   task.Result,
                   CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation canceled",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation faulted",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
                   m_syncContextTaskScheduler);
            }
            base.OnMouseClick(e);
        }
}

那些管理

在职分抛出的未管理万分都封装在System.AggregateException对象中。那个目的会积攒在艺术再次来到的Task或Task<TResult>对象中,要求通过访问Wait()、Result、Exception成员才具体察到那1个。(所以,在访问Result以前,应先观看IsCanceled和IsFaulted属性)

1经从来不访问Task的Wait()、Result、Exception成员,那么您将永恒注意不到那几个卓殊的发生。为了扶持你检查评定到这几个未管理的十分,能够向TaskScheduler对象的UnobservedTaskException事件注册回调函数。每当3个Task被垃圾回收时,借使存在1个从未有过留神到的至极,CLOdyssey的截至器线程会引发这一个事件。

可在事变回调函数中调用UnobservedTaskException伊芙ntArgs对象的SetObserved() 方法来提议已经管理好了老大,从而阻碍CL宝马X3终止线程。不过并不推荐这么做,宁愿终止进度也决不带着早已磨损的图景继续运维。

APM

         使用IAsyncResult设计方式的异步操作是透过名字为 BeginXXX 和 EndXXX 的七个点子来落成,那五个主意分别指初叶和了结异步操作。该情势允许用越来越少的CPU能源(线程)去做越多的操作,.NET Framework好多类也得以达成了该形式,同时大家也足以自定义类来促成该方式(也就是在自定义的类中贯彻重临类型为IAsyncResult接口的BeginXXX方法和收受IAsyncResult包容类型作为唯壹参数的EndXXX方法),其余事委员会托项目也定义了BeginInvoke和EndInvoke方法。比方,FileStream类提供BeginRead和EndRead方法来从文件异步读取字节。那多个办法实现了 Read 方法的异步版本。

调用 BeginXXX 后,应用程序能够继续在调用线程上试行命令,同时异步操作在另二个线程上进行(要是有重回值还应调用 EndXXX利落异步操作,并向该方法传递BeginXXX 方法再次回到的IAsyncResult对象,获取操作的返回值)。

 澳门新萄京官方网站 11

CompletedSynchronously属性值侧重与提醒音信,而非操作

做客异步操作的结果,APM提供了各样方法:

一.在调用BeginXXX方法的线程上调用EndXXX方法来获得异步操作的结果;不过那种艺术会阻塞调用线程,在知情操作达成以往调用线程手艺持续运转。

二.循环查询IAsyncResult的IsComplete属性,操作达成后再调用EndXXX方法来获得操作重临的结果。

叁.IAsyncResult的AsyncWaitHandle属性达成更为灵敏的等待逻辑,调用该属性WaitOne()方法来使三个线程阻塞并等待操作完毕;再调用EndXXX方法来得到操作的结果。WaitHandle.WaitOne()可以钦赐最长的等候时间,如超时重返false;

四. 在调用BeginXXX方法时提供AsyncCallback委托的实例作为参数,在异步操作完结后委托会自动调用(AsyncCallback对象)钦点的秘诀。(首推办法)AsyncCallback委托仅能够调用符合一定格局的格局(唯有八个参数IAsyncResult,且并未有重返值);

澳门新萄京官方网站 12澳门新萄京官方网站 13

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace AsyncCallbackDelegate
{
    public delegate int BinaryOp(int x, int y);
    class Program
    {
        private static bool isDone = false;
        static void Main(string[] args)
        {
            Console.WriteLine("*****  AsyncCallbackDelegate Example *****");
            Console.WriteLine("Main() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            BinaryOp b = new BinaryOp(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10,
              new AsyncCallback(AddComplete),
              "Main() thanks you for adding these numbers.");//传入数据
            // Assume other work is performed here...
            while (!isDone)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Working....");
            }
            Console.ReadLine();
        }

        #region Target for AsyncCallback delegate
        // Don't forget to add a 'using' directive for 
        // System.Runtime.Remoting.Messaging!
        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            //AsyncCallback委托的目标无法调用其他方法中创建的委托
            //IAsyncResult itfAR 实际上是System.Runtime.Remoting.Messaging命名空间AsyncResult类的一个实例
            AsyncResult ar = (AsyncResult)itfAR;
            //AsyncDelegate静态属性返回原始异步委托引用
            BinaryOp b = (BinaryOp)ar.AsyncDelegate;
            Console.WriteLine("10   10 is {0}.", b.EndInvoke(itfAR));

            // Retrieve the informational object and cast it to string.
            //AsyncState属性获取 BeginInvoke第四个参数传入的值
            string msg = (string)itfAR.AsyncState;
            Console.WriteLine(msg);
            isDone = true;
        }

        #endregion

        #region Target for BinaryOp delegate
        static int Add(int x, int y)
        {
            Console.WriteLine("Add() invoked on thread {0}.",
              Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(5000);
            return x   y;
        }
        #endregion
    }
}

AsyncCallback

非凡捕获

在一块儿奉行的章程里面普通处理分外的措施是将可能抛出十二分的代码放到try...catch...finally里面,之所以能够捕获到,是因为发生万分的代码与调用的代码位于同贰个线程。当调用一个异步方法产生极度时,CLCRUISER会捕获并且在EndXXX方法时再也将卓殊抛出抛出,所以异步调用中的卓殊在EndXXX方法出捕获就行了。

class ApmExceptionHandling 
{
   public static void Go() 
  {
      WebRequest webRequest = WebRequest.Create("http://0.0.0.0/");
      webRequest.BeginGetResponse(ProcessWebResponse, webRequest);
      Console.ReadLine();
   }
   private static void ProcessWebResponse(IAsyncResult result) {
      WebRequest webRequest = (WebRequest)result.AsyncState;

      WebResponse webResponse = null;
      try {
         webResponse = webRequest.EndGetResponse(result);
         Console.WriteLine("Content length: "   webResponse.ContentLength);
      }
      catch (WebException we) {
         Console.WriteLine(we.GetType()   ": "   we.Message);
      }
      finally {
         if (webResponse != null) webResponse.Close();
      }
   }
}

APM WinForm UI线程回调

出于AsyncCallback委托回调是从ThreadPool中的线程施行的,由此对此Winform,假诺回调须求操作UI控件,就须要再次回到到UI线程去,常用的七个方法:

1.  Control类落成了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来支撑任何线程更新GUI界面控件的编写制定(将回调方法投递到创建该控件的线程中实施)。

 澳门新萄京官方网站 14

Control类的 Invoke,BeginInvoke 内部贯彻如下:

a) Invoke(同步调用)先判别控件创立线程与当前线程是或不是1致,一样则一向调用委托方法;不然使用Win3二API的PostMessage异步实行,但是Invoke内部会调用IAsyncResult.AsyncWaitHandle等待施行到位。

b) BeginInvoke(异步调用)使用Win3二API的PostMessage 异步实践,并且再次来到IAsyncResult 对象。

运用格局:回调方法中对控件检查评定InvokeRequired值,if true,在该回调中封送一回委托,调用控件的Invoke/ BeginInvoke方法;

 澳门新萄京官方网站 15

贰.GUI(WinForm/WPF)应用程序引进了3个线程管理模型:创制窗口的线程是并世无两能对那一个窗口举行创新的线程;在GUI线程中,平时索要改动异步操作,使GUI线程不封堵并结束响应用户输入。然则,异步操作达成时,由于是用贰个线程池线程达成的,而线程池线程无法更新UI控件。为化解这个主题素材,FCL定义一个System.Threading.SynchronizationContext(线程同步上下文)的基类,其派生对象承担将四个应用程序模型连接到它的线程管理模型。

GUI线程都有叁个和它事关的SynchronizationContext派生对象,使用其静态Current属性获取:SynchronizationContext sc = SynchronizationContext.Current; 将此目的传给其余线程,当二个线程池线程要求让GUI线程更新UI时,调用该对象的sc.Post方法,向Post传递贰个相配SendOrPostCallback委托具名的回调方法(一般是更新UI的操作方法,由GUI线程去奉行),以及贰个要传给回调方法的实参。

SynchronizationContext 的Post方法和Send方法的区分:(分别对应于异步/同步调用)

Post方法将回调方法送人GUI线程的队列,允许程序池线程立即返回,不进行阻塞;Post方法内部调用了BeginInvoke方法;

Send方法也将回调方法送人GUI线程的队列,但随后就会阻塞线程池线程,直到GUI线程完成对回调方法的调用。阻塞线程池线程极有可能造成线程池创建一个新的线程,避免调用该方法;Send方法内部调用了Invoke方法; 

对winform来说是 System.Windows.Forms.WindowsFormsSynchronizationContext是其子类.

Winform窗口出现后,UI线程 SynchronizationContext.Current会被绑定赋值,唯有UI线程的Current不为null。

Public class SendOrPostUI {
   public static void Go() {
      System.Windows.Forms.Application.Run(new MyWindowsForm());
   }
   private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
      // Capture the calling thread's SynchronizationContext-derived object
      SynchronizationContext sc = SynchronizationContext.Current;
      // If there is no SC, just return what was passed in
      if (sc == null) return callback;
      // Return a delegate that, when invoked, posts to the captured SC a method that 
      // calls the original AsyncCallback passing it the IAsyncResult argument
      return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);
   }
   private sealed class MyWindowsForm : System.Windows.Forms.Form {
      public MyWindowsForm() {
         Text = "Click in the window to start a Web request";
         Width = 400; Height = 100;
      }
      protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
         // The GUI thread initiates the asynchronous Web request 
         Text = "Web request initiated";
         var webRequest = WebRequest.Create("http://Wintellect.com/");
         webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);
         base.OnMouseClick(e);
      }
      private void ProcessWebResponse(IAsyncResult result) {
         // If we get here, this must be the GUI thread, it's OK to update the UI
         var webRequest = (WebRequest)result.AsyncState;
         using (var webResponse = webRequest.EndGetResponse(result)) {
            Text = "Content length: "   webResponse.ContentLength;
         }
      }
   }
}

比较二种格局其实差不太多,三个是回调内再次卷入,一个是包裹原来的回调。不过SynchronizationContext业务层与UI分离来说的话是相比较好;

1.1 简介

在事先的多少个章节中,就线程的接纳和10二线程相关的内容举行了介绍。因为线程涉及到异步、同步、万分传递等难点,所以在项目中央银行使102线程的代价是相比高昂的,要求编写制定大量的代码来完成科学和健壮性。

为了消除那样一些的难点,在.Net Framework 4.0中引入了二个有关一步操作的API。它称作义务并行库(Task Parallel Library)。然后在.Net Framwork 4.5中对它进行了细微的精雕细刻,本文的案例都是用新型版本的TPL库,而且大家还足以使用C# 5.0的新特点await/async来简化TAP编制程序,当然这是随后才介绍的。

TPL内部采用了线程池,不过效能越来越高。在把线程归还回线程池在此以前,它会在同1线程中逐1推行多少Task,那样防止了部分小职分上下文切换浪费时间片的标题。

任务是目标,当中封装了以异步格局实行的办事,可是委托也是包裹了代码的目的。义务和嘱托的差别在于,委托是同步的,而任务是异步的。

在本章中,大家将议和谈哪些行使TPL库来展开职务之间的整合同步,怎样将残留的APM和EAP形式转变为TPL格局等等。

 

TAP

.NET肆.0 中引入了新的异步编制程序模型“基于义务的异步编制程序模型(TAP)”,并且推荐大家在开垦新的三十二线程应用程序中首推TAP,在.NET四.5中更为对TPL库举行了大批量的优化与改良(async和await)。那未来本身先介绍下TAP具备何样优势:

  1. 职务调解器(TaskScheduler)依赖于底层的线程池引擎,可自定义一个TaskScheduler改换调解算法,同时不转移代码或编制程序模型。通过有些队列的天职内联化(task inlining)和办事窃取(work-stealing)机制而发起了大批量职务,Task可以为大家提高程序质量。
  2. 能够利用PreferFairness标记,获取与ThreadPool.QueueUserWorkItem或然2个寄托的BeginInvoke相同的线程池行为。

        叁.  轻易落成职务等待、职务撤销、一而再职责、极度管理(System.AggregateException)、GUI线程操作。

       四.  在任务运营后,能够随时以职分延续的样式登记回调。

       5.  丰富利用现存的线程,幸免创立不要求的额外线程。

       6.  结合C#5.0引进async和await关键字轻便落成“异步方法”。

APM转换为TAP:

动用TaskFactory的FromAsync方法,传递多少个实参:BeginXxx方法、EndXxx方法、Object状态、可选的TaskCreationOptions值,重临对3个Task对象的引用;

private static void ConvertingApmToTask() {
      // Instead of this:
      WebRequest webRequest = WebRequest.Create("http://Wintellect.com/");
      webRequest.BeginGetResponse(result => {
         WebResponse webResponse = null;
         try {
            webResponse = webRequest.EndGetResponse(result);
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (WebException we) {
            Console.WriteLine("Failed: "   we.GetBaseException().Message);
         }
         finally {
            if (webResponse != null) webResponse.Close();
         }
      }, null);
      Console.ReadLine();  // for testing purposes
      // Make a Task from an async operation that FromAsync starts
      webRequest = WebRequest.Create("http://Wintellect.com/");
      var t1 = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse, null, TaskCreationOptions.None);
      var t2 = t1.ContinueWith(task => {
         WebResponse webResponse = null;
         try {
            webResponse = task.Result;
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (AggregateException ae) {
            if (ae.GetBaseException() is WebException)
               Console.WriteLine("Failed: "   ae.GetBaseException().Message);
            else throw;
         }
         finally { if (webResponse != null) webResponse.Close(); }
      });
      try {t2.Wait();  // for testing purposes only}
      catch (AggregateException) { }
   }

EAP转换成TAP:

利用System.Threading.Tasks.TaskCompletionSource类举行打包;

澳门新萄京官方网站 16

当协会1个TaskCompletionSource对象,也会变动2个Task,可通过其Task属性获取;当2个异步操作落成时,它应用TaskCompletionSource对象来设置它因为何而形成,撤消,未管理的那几个只怕它的结果。调用有些SetXxx方法,能够安装底层Task对象的动静。

private sealed class MyFormTask : System.Windows.Forms.Form {
      protected override void OnClick(EventArgs e) {
         // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
         WebClient wc = new WebClient();
         // Create the TaskCompletionSource and its underlying Task object
         var tcs = new TaskCompletionSource<String>();
         // When a string completes downloading, the WebClient object raises the 
         // DownloadStringCompleted event which will invoke our ProcessString method
         wc.DownloadStringCompleted  = (sender, ea) => {
            // This code always executes on the GUI thread; set the Task’s state
            if (ea.Cancelled) tcs.SetCanceled();
            else if (ea.Error != null) tcs.SetException(ea.Error);
            else tcs.SetResult(ea.Result);
         };
         // Have the Task continue with this Task that shows the result in a message box
// NOTE: The TaskContinuationOptions.ExecuteSynchronously flag is required to have this code
         // run on the GUI thread; without the flag, the code runs on a thread pool thread 
         tcs.Task.ContinueWith(t => {
            try { System.Windows.Forms.MessageBox.Show(t.Result);}
            catch (AggregateException ae) {
               System.Windows.Forms.MessageBox.Show(ae.GetBaseException().Message);
            }
         }, TaskContinuationOptions.ExecuteSynchronously);
         // Start the asynchronous operation (this is like calling a BeginXxx method)
         wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
         base.OnClick(e);
      }
   }

实现了TAP的类:存在XxxTaskAsync的方法, 帮助异步操作的撤废和速度的告知的功能;

注销:能够由此合作式裁撤形式,向异步方法传入CancellationToken 参数,通过调用其ThrowIfCancellationRequested方法来定时检查操作是不是早已撤回;

进程报告:能够经过IProgress<T>接口来促成速度报告的效应;

更新GUI: TaskScheduler.FromCurrentSynchronizationContext()获取同步上下文职务调节器,将关系该对象的有所任务都调节给GUI线程,使职务代码能打响更新UI;

private sealed class MyForm : System.Windows.Forms.Form {
        public MyForm() {
            Text = "Synchronization Context Task Scheduler Demo";
            Visible = true; Width = 400; Height = 100;
        }
         private static Int32 Sum(CancellationToken ct, Int32 n) {
        Int32 sum = 0;
        for (; n > 0; n--) {
            // The following line throws OperationCanceledException when Cancel 
            // is called on the CancellationTokenSource referred to by the token
            ct.ThrowIfCancellationRequested();
            //Thread.Sleep(0);   // Simulate taking a long time
            checked { sum  = n; }
        }
        return sum;
       }
        private readonly TaskScheduler m_syncContextTaskScheduler =
           TaskScheduler.FromCurrentSynchronizationContext();
        private CancellationTokenSource m_cts;
        protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
            if (m_cts != null) {    // An operation is in flight, cancel it
                m_cts.Cancel();
                m_cts = null;
            } else {                // An operation is not in flight, start it
                Text = "Operation running";
                m_cts = new CancellationTokenSource();
           // This task uses the default task scheduler and executes on a thread pool thread
                var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token);
                t.Start();
 // These tasks use the synchronization context task scheduler and execute on the GUI thread
                t.ContinueWith(task => Text = "Result: "   task.Result,
                   CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation canceled",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation faulted",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
                   m_syncContextTaskScheduler);
            }
            base.OnMouseClick(e);
        }
}

可怜管理

在任务抛出的未管理格外都封装在System.AggregateException对象中。那么些目的会积存在情势重回的Task或Task<TResult>对象中,要求经过拜访Wait()、Result、Exception成员技艺观测到分外。(所以,在造访Result在此之前,应先观看IsCanceled和IsFaulted属性)

即使一直不访问Task的Wait()、Result、Exception成员,那么你将恒久注意不到那么些尤其的发出。为了援救你检查测试到那个未管理的要命,能够向TaskScheduler对象的UnobservedTaskException事件注册回调函数。每当三个Task被垃圾回收时,假如存在一个不曾放在心上到的不得了,CL宝马X伍的了断器线程会引发那一个事件。

可在事变回调函数中调用UnobservedTaskException伊芙ntArgs对象的SetObserved() 方法来建议已经管理好了相当,从而阻碍CL大切诺基终止线程。不过并不引入这么做,宁愿终止进度也毫不带着已经损坏的地方继续运维。

Async /Await

在.NET Framework 四.0中增添.NET Framework 四.5中新的异步操作库(async/await),该包由八个库组成:Microsoft.Bcl、Microsoft.Bcl.Async和Microsoft.Bcl.Build。

Install-Package Microsoft.Bcl.Async

注:asp.net 框架必要求晋级.net framework框架技巧动用 async/await

 

C# 伍引进了异步函数(asynchrnous function)的定义。平时是指用async修饰符表明的,可

含有await表明式的法子或无名函数;

async关键字成立了叁个状态机,类似于yield return语句;await关键字只好用于有用async修饰符表明的艺术。async修饰符只可以用来重返Task/Task<TResult>或void的格局。await只好用来调用重临Task/Task<TResult>的方法;await会解除线程的隔断,达成调用的天职;等待职务成功后,获取结果,然后推行await关键字背后的代码;编写翻译器会把await的表明式后的代码应用 Task.ContinueWith 打包了起来,回调时默许使用当前线程的同步上下文职务调整器;若是不选拔同样的联合具名上下文,必须调用Task实例的ConfigureAwait(false)方法;

await msg.Content.ReadAsStringAsync().ConfigureAwait(false);

异步方法的注解语法与其他措施完全壹致,只是要含有async上下文关键字。async能够出

现行反革命归来类型在此之前的其他任务。async修饰符在改换的代码中并未有效果,也可省略不写,它分明颁布了你的预料,告诉编写翻译器能够主动搜寻await表达式,也能够寻找应该调换到异步调用和await表明式的块调用。

调用者和异步方法之间是通过重返值来通讯的。异步函数的回到类型只好为:

Void 、Task、Task<TResult>;Task和Task<TResult>类型都意味着贰个大概还未成功的操作。 Task<TResult>承袭自Task。二者的分歧是,Task<TResult>表示三个重回值为T类型的操作,而Task则无需发出重返值。在某种意义上,你能够感觉Task便是Task<void>类型;

故此将异步方法设计为可以重临void,是为了和事件管理程序包容。

异步方法具名的约束:全体参数都不可能利用out或ref修饰符。

澳门新萄京官方网站 17

 

IO操作的MDA(Direct memory access)格局:间接待上访问内部存款和储蓄器,是一种不经过CPU而直白开始展览内部存款和储蓄器数据存储的数据交流形式,差不离可以不损...

EAP

EAP是为了更便于处理UI的更新推出的模式,主要优点:它同Visual Studio UI设计器进行了很好的集成,可将大多数实现了EAP的类拖放到设计平面(design surface)上,双击控件对应的XXXCompleted事件名,会自动生成事件的回调方法,并将方法同事件自身联系起来。EAP保证事件在应用程序的GUI线程上引发,允许事件回调方法中的代码更新UI控件;

EAP另一重要功能:支持EAP的类自动将应用程序模型映射到它的线程处理模型;EAP类在内部使用SynchronizationContext类。有的EAP类提供了取消、进度报告功能。

   FCL中唯有壹三个品类达成了EAP方式,一般有八个XXXAsync方法和三个相应的XXXCompleted事件,以及那个方法的联合签名版本:

*       System.Object的派生类型:*

*                  System.Activies.WorkflowInvoke  *

*                  System.Deployment.Application.ApplicationDeployment*

*                  System.Deployment.Application.InPlaceHosingManager*

*                  System.Net.Mail.SmtpClient*

*                  System.Net.PeerToPeer.PeerNameResolver*

*                  System.Net.PeerToPeer.Collaboration.ContactManager*

*                  System.Net.PeerToPeer.Collaboration.Peer*

*                  System.Net.PeerToPeer.Collaboration.PeerContact*

澳门新萄京官方网站:中档的二10拾二线程_职务并行库,异步编制程序。*                  System.Net.PeerToPeer.Collaboration.PeerNearMe*

*                  System.ServiceModel.Activities.WorkflowControlClient*

*                  System.ServiceModel.Discovery.AnnoucementClient*

*                  System.ServiceModel.Discovery.DiscoveryClient*

*      System.ComponentModel.Component的派生类型:*

                  System.ComponentModel.BackgroundWorker

                  System.Media.SoundPlay

                  System.Net.WebClient

                  System.Net.NetworkInformation.Ping

                  System.Windows.Forms.PictureBox(承袭于Control类,Control类派生于Component类)

private sealed class MyForm : System.Windows.Forms.Form {
    protected override void OnClick(EventArgs e) {
      // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
      WebClient wc = new WebClient();
      // When a string completes downloading, the WebClient object raises the 
      // DownloadStringCompleted event which will invoke our ProcessString method         
      wc.DownloadStringCompleted  = ProcessString;
      // Start the asynchronous operation (this is like calling a BeginXxx method)
      wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
      base.OnClick(e);
    }
    // This method is guaranteed to be called via the GUI thread
    private void ProcessString(Object sender, DownloadStringCompletedEventArgs e) {
      // If an error occurred, display it; else display the downloaded string
      System.Windows.Forms.MessageBox.Show((e.Error != null) ? e.Error.Message : e.Result);
      }
   }

BackgroundWorker:唯有该品种用于可用以施行异步的乘除范围的工作;提供多个事件:

DoWork:向这几个事件登记的主意应该包括总括范围的代码。这么些事件由贰个线程池线程调用RunWorkerAsync(四个重载方法,带参的章程是向DoWork登记的措施的DoWork伊芙ntArgs参数对象的Argument属性传值,只万幸登记的艺术中(如e.Argument)获取,Result属性必须设置成总结范围的操作希望再次回到的值)时引发;

ProgressChanged:向那么些事件登记的主意应该包蕴使用进程音讯来更新UI的代码。那些事件接二连叁在GUI线程上掀起。DoWork登记的措施必须定时调用BackgroundWorker的ReportProgress方法来诱惑ProgressChanged事件;

RunWorkerCompleted:向那些事件登记的办法应该包罗使用总结范围操作的结果对UI举行翻新的代码。那个事件接二连3在GUI线程上引发。Result获取表示异步操作的结果;

国有性质:CancellationPending(标记是还是不是已呼吁撤废后台操作)、IsBusy(标志是还是不是正在运维异步操作)、WorkReportsProgress(获取/设置是不是报告进程更新)、WorkerSupportsCancellation(获取/设置是还是不是匡助异步打消)

公家措施:CancelAsync(请求撤消挂起的后台操作)、ReportProgress、RunWorkerAsync

异常

老大不会抛出。在XXXCompleted事件管理方法中,必须询问AsyncCompleted伊夫ntArgs的Exception属性,看它是还是不是null。要是或不是null,就亟须采用if语句判别Exception派生对象的品类,而不是采纳catch块。

1.贰 创立职务

在本节中,重就算出现说法了如何创制1个职分。其利害攸关选拔了System.Threading.Tasks命名空间下的Task类。该类能够被实例化并且提供了壹组静态方法,能够方便火速的创立任务。

在底下实例代码中,分别延时了三种普及的职分创建格局,并且创制职务是足以内定职务创制的选项,从而达到最优的创造格局。

TaskCreationOptions中1共有多少个枚举,枚举是能够使用|运算符组合定义的。其枚举如下表所示。

成员名称 说明
AttachedToParent 指定将任务附加到任务层次结构中的某个父级。 默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。 可以使用 TaskContinuationOptions.AttachedToParent 选项以便将父任务和子任务同步。请注意,如果使用 DenyChildAttach 选项配置父任务,则子任务中的 AttachedToParent 选项不起作用,并且子任务将作为分离的子任务执行。有关详细信息,请参阅附加和分离的子任务
DenyChildAttach 指定任何尝试作为附加的子任务执行(即,使用 AttachedToParent 选项创建)的子任务都无法附加到父任务,会改成作为分离的子任务执行。 有关详细信息,请参阅附加和分离的子任务
HideScheduler 防止环境计划程序被视为已创建任务的当前计划程序。 这意味着像 StartNew 或 ContinueWith 创建任务的执行操作将被视为 Default 当前计划程序。
LongRunning 指定任务将是长时间运行的、粗粒度的操作,涉及比细化的系统更少、更大的组件。 它会向 TaskScheduler 提示,过度订阅可能是合理的。 可以通过过度订阅创建比可用硬件线程数更多的线程。 它还将提示任务计划程序:该任务需要附加线程,以使任务不阻塞本地线程池队列中其他线程或工作项的向前推动。
None 指定应使用默认行为。
PreferFairness 提示 TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。
RunContinuationsAsynchronously 强制异步执行添加到当前任务的延续任务。请注意,RunContinuationsAsynchronously 成员在以 .NET Framework 4.6 开头的 TaskCreationOptions 枚举中可用。
static void Main(string[] args)
{
    // 使用构造方法创建任务
    var t1 = new Task(() => TaskMethod("Task 1"));
    var t2 = new Task(() => TaskMethod("Task 2"));

    // 需要手动启动
    t2.Start();
    t1.Start();

    // 使用Task.Run 方法启动任务  不需要手动启动
    Task.Run(() => TaskMethod("Task 3"));

    // 使用 Task.Factory.StartNew方法 启动任务 实际上就是Task.Run
    Task.Factory.StartNew(() => TaskMethod("Task 4"));

    // 在StartNew的基础上 添加 TaskCreationOptions.LongRunning 告诉 Factory该任务需要长时间运行
    // 那么它就会可能会创建一个 非线程池线程来执行任务  
    Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);

    ReadLine();
}

static void TaskMethod(string name)
{
    WriteLine($"任务 {name} 运行,线程 id {CurrentThread.ManagedThreadId}. 是否为线程池线程: {CurrentThread.IsThreadPoolThread}.");
}

运转结果如下图所示。

澳门新萄京官方网站 18

4.1 简介

Async /Await

在.NET Framework 四.0中增加.NET Framework 4.5中新的异步操作库(async/await),该包由八个库组成:Microsoft.Bcl、Microsoft.Bcl.Async和Microsoft.Bcl.Build。

Install-Package Microsoft.Bcl.Async

注:asp.net 框架必供给进级.net framework框架才具选拔 async/await

假定那么些新闻是“Message : Could not load file or assembly 'System.Core, Version=二.0.伍.0, Culture=neutral, PublicKeyToken=7cec85d7bea779八e, Retargetable=Yes' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)”,

那需求您去微软官方网站下载.net四.0的KB2468871补丁来安装。

C# 伍引进了异步函数(asynchrnous function)的定义。经常是指用async修饰符表明的,可

含蓄await表明式的格局或佚名函数;

async关键字创建了多少个状态机,类似于yield return语句;await关键字只好用于有用async修饰符表明的章程。async修饰符只好用来重回Task/Task<TResult>或void的措施。await只好用来调用再次来到Task/Task<TResult>的艺术;await会解除线程的封堵,实现调用的职责;等待任务达成后,获取结果,然后实行await关键字背后的代码;编译器会把await的表明式后的代码应用 Task.ContinueWith 打包了4起,回调时暗中认可使用当前线程的联合签名上下文职分调整器;如若不利用同一的协同上下文,必须调用Task实例的ConfigureAwait(false)方法;

await msg.Content.ReadAsStringAsync().ConfigureAwait(false);

异步方法的扬言语法与其他措施完全等同,只是要包涵async上下文关键字。async能够出

近来归来类型以前的别的岗位。async修饰符在退换的代码中绝非意义,也可省略不写,它显明表达了你的料想,告诉编写翻译器能够积极搜寻await表明式,也足以寻觅应该转变来异步调用和await表明式的块调用。

调用者和异步方法之间是透过重回值来通讯的。异步函数的回到类型只可以为:

Void 、Task、Task<TResult>;Task和Task<TResult>类型都表示贰个恐怕还未产生的操作。 Task<TResult>承袭自Task。2者的分别是,Task<TResult>表示叁个重回值为T类型的操作,而Task则不须求发出再次来到值。在某种意义上,你能够感觉Task正是Task<void>类型;

因此将异步方法设计为可以回去void,是为着和事件管理程序兼容。

异步方法签字的自律:全部参数都不能够选取out或ref修饰符。

澳门新萄京官方网站 19

 

TAP

.NET肆.0 中引进了新的异步编制程序模型“基于职分的异步编程模型(TAP)”,并且推荐我们在开垦新的十二线程应用程序中首荐TAP,在.NET四.第55中学进一步对TPL库进行了汪洋的优化与考订(async和await)。那今后自己先介绍下TAP具备何样优势:

  1. 任务调治器(TaskScheduler)注重于底层的线程池引擎,可自定义三个TaskScheduler更动调解算法,同时不改动代码或编制程序模型。通过一些队列的职务内联化(task inlining)和工作窃取(work-stealing)机制而发起了大气职责,Task可感到大家升高程序质量。
  2. 可以利用PreferFairness标记,获取与ThreadPool.QueueUserWorkItem也许叁个信托的BeginInvoke一样的线程池行为。

        三.  轻巧达成职分等待、任务撤销、一而再职务、极度管理(System.AggregateException)、GUI线程操作。

       四.  在义务运维后,能够随时以职责三番五次的花样登记回调。

       伍.  丰富利用现存的线程,防止创制不要求的额外线程。

       6.  结合C#5.0引进async和await关键字轻易达成“异步方法”。

APM转换为TAP:

接纳TaskFactory的FromAsync方法,传递多少个实参:BeginXxx方法、EndXxx方法、Object状态、可选的TaskCreationOptions值,重回对3个Task对象的引用;

private static void ConvertingApmToTask() {
      // Instead of this:
      WebRequest webRequest = WebRequest.Create("http://Wintellect.com/");
      webRequest.BeginGetResponse(result => {
         WebResponse webResponse = null;
         try {
            webResponse = webRequest.EndGetResponse(result);
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (WebException we) {
            Console.WriteLine("Failed: "   we.GetBaseException().Message);
         }
         finally {
            if (webResponse != null) webResponse.Close();
         }
      }, null);
      Console.ReadLine();  // for testing purposes
      // Make a Task from an async operation that FromAsync starts
      webRequest = WebRequest.Create("http://Wintellect.com/");
      var t1 = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse, null, TaskCreationOptions.None);
      var t2 = t1.ContinueWith(task => {
         WebResponse webResponse = null;
         try {
            webResponse = task.Result;
            Console.WriteLine("Content length: "   webResponse.ContentLength);
         }
         catch (AggregateException ae) {
            if (ae.GetBaseException() is WebException)
               Console.WriteLine("Failed: "   ae.GetBaseException().Message);
            else throw;
         }
         finally { if (webResponse != null) webResponse.Close(); }
      });
      try {t2.Wait();  // for testing purposes only}
      catch (AggregateException) { }
   }

EAP转换成TAP:

选择System.Threading.Tasks.TaskCompletionSource类进行李包裹装;

澳门新萄京官方网站 20

当组织二个TaskCompletionSource对象,也会变动二个Task,可经过其Task属性获取;当贰个异步操作完结时,它接纳TaskCompletionSource对象来设置它因为何而形成,撤除,未管理的老大只怕它的结果。调用有个别SetXxx方法,能够安装底层Task对象的动静。

private sealed class MyFormTask : System.Windows.Forms.Form {
      protected override void OnClick(EventArgs e) {
         // The System.Net.WebClient class supports the Event-based Asynchronous Pattern
         WebClient wc = new WebClient();
         // Create the TaskCompletionSource and its underlying Task object
         var tcs = new TaskCompletionSource<String>();
         // When a string completes downloading, the WebClient object raises the 
         // DownloadStringCompleted event which will invoke our ProcessString method
         wc.DownloadStringCompleted  = (sender, ea) => {
            // This code always executes on the GUI thread; set the Task’s state
            if (ea.Cancelled) tcs.SetCanceled();
            else if (ea.Error != null) tcs.SetException(ea.Error);
            else tcs.SetResult(ea.Result);
         };
         // Have the Task continue with this Task that shows the result in a message box
// NOTE: The TaskContinuationOptions.ExecuteSynchronously flag is required to have this code
         // run on the GUI thread; without the flag, the code runs on a thread pool thread 
         tcs.Task.ContinueWith(t => {
            try { System.Windows.Forms.MessageBox.Show(t.Result);}
            catch (AggregateException ae) {
               System.Windows.Forms.MessageBox.Show(ae.GetBaseException().Message);
            }
         }, TaskContinuationOptions.ExecuteSynchronously);
         // Start the asynchronous operation (this is like calling a BeginXxx method)
         wc.DownloadStringAsync(new Uri("http://Wintellect.com"));
         base.OnClick(e);
      }
   }

实现了TAP的类:存在XxxTaskAsync的方法, 帮助异步操作的撤废和速度的告知的成效;

注销:能够经过同盟式撤消方式,向异步方法传入CancellationToken 参数,通过调用其ThrowIfCancellationRequested方法来定期检查操作是还是不是曾经撤回;

进程报告:能够通过IProgress<T>接口来得以落成速度报告的功力;

履新GUI: TaskScheduler.FromCurrentSynchronizationContext()获取同步上下文职务调整器,将关乎该目的的具备职责都调节给GUI线程,使任务代码能学有所成更新UI;

private sealed class MyForm : System.Windows.Forms.Form {
        public MyForm() {
            Text = "Synchronization Context Task Scheduler Demo";
            Visible = true; Width = 400; Height = 100;
        }
         private static Int32 Sum(CancellationToken ct, Int32 n) {
        Int32 sum = 0;
        for (; n > 0; n--) {
            // The following line throws OperationCanceledException when Cancel 
            // is called on the CancellationTokenSource referred to by the token
            ct.ThrowIfCancellationRequested();
            //Thread.Sleep(0);   // Simulate taking a long time
            checked { sum  = n; }
        }
        return sum;
       }
        private readonly TaskScheduler m_syncContextTaskScheduler =
           TaskScheduler.FromCurrentSynchronizationContext();
        private CancellationTokenSource m_cts;
        protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
            if (m_cts != null) {    // An operation is in flight, cancel it
                m_cts.Cancel();
                m_cts = null;
            } else {                // An operation is not in flight, start it
                Text = "Operation running";
                m_cts = new CancellationTokenSource();
           // This task uses the default task scheduler and executes on a thread pool thread
                var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token);
                t.Start();
 // These tasks use the synchronization context task scheduler and execute on the GUI thread
                t.ContinueWith(task => Text = "Result: "   task.Result,
                   CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation canceled",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation faulted",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
                   m_syncContextTaskScheduler);
            }
            base.OnMouseClick(e);
        }
}

那些管理

在职务抛出的未管理万分都封装在System.AggregateException对象中。那些目的会积攒在措施再次回到的Task或Task<TResult>对象中,须求通过走访Wait()、Result、Exception成员手艺体察到卓殊。(所以,在访问Result之前,应先阅览IsCanceled和IsFaulted属性)

举例平昔不访问Task的Wait()、Result、Exception成员,那么您将长久注意不到这几个相当的发生。为了扶助您检查评定到那几个未处理的可怜,能够向TaskScheduler对象的UnobservedTaskException事件注册回调函数。每当一个Task被垃圾回收时,假使存在八个从未有过注意到的11分,CLSportage的停止器线程会引发那几个事件。

可在事变回调函数中调用UnobservedTaskException伊芙ntArgs对象的SetObserved() 方法来提出已经处理好了充足,从而阻碍CLPAJERO终止线程。但是并不引入这么做,宁愿终止进程也决不带着已经损坏的气象继续运行。

壹.叁 使用职务实行基本的操作

在本节中,使用义务实行基本的操作,并且赢得任务施行到位后的结果值。本节内容比较简单,在此不做过多介绍。

示范代码如下,在主线程中要获得结果值,常用的诀要正是造访task.Result属性,假诺义务线程还没实施落成,那么会阻塞主线程,直到线程实施完。假若任务线程实行落成,那么将间接获得运算的结果值。

Task 3中,使用了task.Status来打字与印刷线程的景况,线程种种情状的具体意思,将在下一节中牵线。

static void Main(string[] args)
{
    // 直接执行方法 作为参照
    TaskMethod("主线程任务");

    // 访问 Result属性 达到运行结果
    Task<int> task = CreateTask("Task 1");
    task.Start();
    int result = task.Result;
    WriteLine($"运算结果: {result}");

    // 使用当前线程,同步执行任务
    task = CreateTask("Task 2");
    task.RunSynchronously();
    result = task.Result;
    WriteLine($"运算结果:{result}");

    // 通过循环等待 获取运行结果
    task = CreateTask("Task 3");
    WriteLine(task.Status);
    task.Start();

    while (!task.IsCompleted)
    {
        WriteLine(task.Status);
        Sleep(TimeSpan.FromSeconds(0.5));
    }

    WriteLine(task.Status);
    result = task.Result;
    WriteLine($"运算结果:{result}");

    Console.ReadLine();
}

static Task<int> CreateTask(string name)
{
    return new Task<int>(() => TaskMethod(name));
}

static int TaskMethod(string name)
{
    WriteLine($"{name} 运行在线程 {CurrentThread.ManagedThreadId}上. 是否为线程池线程 {CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(2));

    return 42;
}

运行结果如下,可知Task 1Task 2均是运作在主线程上,并非线程池线程。

澳门新萄京官方网站 21

 

Async /Await

在.NET Framework 4.0中加多.NET Framework 四.5中新的异步操作库(async/await),该包由八个库组成:Microsoft.Bcl、Microsoft.Bcl.Async和Microsoft.Bcl.Build。

Install-Package Microsoft.Bcl.Async

注:asp.net 框架必要求进级.net framework框架技能应用 async/await

假诺不行消息是“Message : Could not load file or assembly 'System.Core, Version=贰.0.5.0, Culture=neutral, PublicKeyToken=柒cec八伍d7bea779八e, Retargetable=Yes' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x801310四七)”,

那须要你去微软官方网站下载.net四.0的KB2468871补丁来安装。

C# 5引进了异步函数(asynchrnous function)的概念。经常是指用async修饰符评释的,可

包涵await表明式的法子或无名氏函数;

async关键字创制了2个状态机,类似于yield return语句;await关键字只可以用来有用async修饰符评释的艺术。async修饰符只好用于重临Task/Task<TResult>或void的不二等秘书诀。await只可以用来调用重回Task/Task<TResult>的情势;await会解除线程的围堵,完毕调用的天职;等待职责到位后,获取结果,然后实施await关键字背后的代码;编译器会把await的表明式后的代码应用 Task.ContinueWith 装进了四起,回调时暗许使用当前线程的联手上下文任务调节器;如若不使用同样的共同上下文,必须调用Task实例的ConfigureAwait(false)方法;

await msg.Content.ReadAsStringAsync().ConfigureAwait(false);

异步方法的注解语法与其余方法完全同样,只是要含有async上下文关键字。async能够出

至今重返类型以前的别的岗位。async修饰符在转变的代码中从未效劳,也可省略不写,它可想而知表明了你的预料,告诉编写翻译器能够积极搜寻await表明式,也足以搜索应该转变成异步调用和await表明式的块调用。

调用者和异步方法之间是经过重返值来通讯的。异步函数的回到类型只可以为:

Void 、Task、Task<TResult>;Task和Task<TResult>类型都意味三个或然还未成功的操作。 Task<TResult>承继自Task。二者的区别是,Task<TResult>表示叁个重临值为T类型的操作,而Task则没有必要发出再次回到值。在某种意义上,你能够认为Task正是Task<void>类型;

从而将异步方法设计为能够回来void,是为了和事件管理程序包容。

异步方法签字的约束:全数参数都不可能选取out或ref修饰符。

澳门新萄京官方网站 22

 

一.肆 组合义务

在本节中,展现了任务之中1个强劲的效应,那正是整合职务。通过结合职分可很好的叙述职分与职务之间的异步、同步关系,大大下降了编制程序的难度。

结合职责入眼是通过task.ContinueWith()task.WhenAny()task.WhenAll()等和task.GetAwaiter().OnCompleted()主意来实现。

在使用task.ContinueWith()艺术时,须要留意它也可传递一种类的枚举选项TaskContinuationOptions,该枚举选项和TaskCreationOptions好像,其现实定义如下表所示。

成员名称 说明
AttachedToParent 如果延续为子任务,则指定将延续附加到任务层次结构中的父级。 只有当延续前面的任务也是子任务时,延续才可以是子任务。 默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。 可以使用 TaskContinuationOptions.AttachedToParent 选项以便将父任务和子任务同步。请注意,如果使用 DenyChildAttach 选项配置父任务,则子任务中的 AttachedToParent 选项不起作用,并且子任务将作为分离的子任务执行。有关更多信息,请参见Attached and Detached Child Tasks
DenyChildAttach 指定任何使用 TaskCreationOptions.AttachedToParent 选项创建,并尝试作为附加的子任务执行的子任务(即,由此延续创建的任何嵌套内部任务)都无法附加到父任务,会改成作为分离的子任务执行。 有关详细信息,请参阅附加和分离的子任务
ExecuteSynchronously 指定应同步执行延续任务。 指定此选项后,延续任务在导致前面的任务转换为其最终状态的相同线程上运行。如果在创建延续任务时已经完成前面的任务,则延续任务将在创建此延续任务的线程上运行。 如果前面任务的 CancellationTokenSource 已在一个 finally(在 Visual Basic 中为 Finally)块中释放,则使用此选项的延续任务将在该 finally 块中运行。 只应同步执行运行时间非常短的延续任务。由于任务以同步方式执行,因此无需调用诸如 Task.Wait 的方法来确保调用线程等待任务完成。
HideScheduler 指定由延续通过调用方法(如 Task.RunTask.ContinueWith)创建的任务将默认计划程序 (TaskScheduler.Default) 视为当前的计划程序,而不是正在运行该延续的计划程序。
LazyCancellation 在延续取消的情况下,防止延续的完成直到完成先前的任务。
LongRunning 指定延续将是长期运行的、粗粒度的操作。 它会向 TaskScheduler 提示,过度订阅可能是合理的。
None 如果未指定延续选项,应在执行延续任务时使用指定的默认行为。 延续任务在前面的任务完成后以异步方式运行,与前面任务最终的 Task.Status 属性值无关。 如果延续为子任务,则会将其创建为分离的嵌套任务。
NotOnCanceled 指定不应在延续任务前面的任务已取消的情况下安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.Canceled,则前面的任务会取消。 此选项对多任务延续无效。
NotOnFaulted 指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.Faulted,则前面的任务会引发未处理的异常。 此选项对多任务延续无效。
NotOnRanToCompletion 指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.RanToCompletion,则前面的任务会运行直至完成。 此选项对多任务延续无效。
OnlyOnCanceled 指定只应在延续前面的任务已取消的情况下安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.Canceled,则前面的任务会取消。 此选项对多任务延续无效。
OnlyOnFaulted 指定只有在延续任务前面的任务引发了未处理异常的情况下才应安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.Faulted,则前面的任务会引发未处理的异常。OnlyOnFaulted 选项可保证前面任务中的 Task.Exception 属性不是 null。 你可以使用该属性来捕获异常,并确定导致任务出错的异常。 如果你不访问 Exception 属性,则不会处理异常。 此外,如果尝试访问已取消或出错的任务的 Result 属性,则会引发一个新异常。此选项对多任务延续无效。
OnlyOnRanToCompletion 指定只应在延续任务前面的任务已完成运行的情况下才安排延续任务。 如果前面任务完成的 Task.Status 属性是 TaskStatus.RanToCompletion,则前面的任务会运行直至完成。 此选项对多任务延续无效。
PreferFairness 提示 TaskScheduler 按任务计划的顺序安排任务,因此较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。
RunContinuationsAsynchronously 指定应异步运行延续任务。 此选项优先于 TaskContinuationOptions.ExecuteSynchronously。

演示代码如下所示,使用ContinueWith()OnCompleted()办法结合了任务来运作,搭配区别的TaskCreationOptionsTaskContinuationOptions来促成区别的效能。

static void Main(string[] args)
{
    WriteLine($"主线程 线程 Id {CurrentThread.ManagedThreadId}");

    // 创建两个任务
    var firstTask = new Task<int>(() => TaskMethod("Frist Task",3));
    var secondTask = new Task<int>(()=> TaskMethod("Second Task",2));

    // 在默认的情况下 ContiueWith会在前面任务运行后再运行
    firstTask.ContinueWith(t => WriteLine($"第一次运行答案是 {t.Result}. 线程Id {CurrentThread.ManagedThreadId}. 是否为线程池线程: {CurrentThread.IsThreadPoolThread}"));

    // 启动任务
    firstTask.Start();
    secondTask.Start();

    Sleep(TimeSpan.FromSeconds(4));

    // 这里会紧接着 Second Task运行后运行, 但是由于添加了 OnlyOnRanToCompletion 和 ExecuteSynchronously 所以会由运行SecondTask的线程来 运行这个任务
    Task continuation = secondTask.ContinueWith(t => WriteLine($"第二次运行的答案是 {t.Result}. 线程Id {CurrentThread.ManagedThreadId}. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}"),TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);

    // OnCompleted 是一个事件  当contiuation运行完成后 执行OnCompleted Action事件
    continuation.GetAwaiter().OnCompleted(() => WriteLine($"后继任务完成. 线程Id {CurrentThread.ManagedThreadId}. 是否为线程池线程 {CurrentThread.IsThreadPoolThread}"));

    Sleep(TimeSpan.FromSeconds(2));
    WriteLine();

    firstTask = new Task<int>(() => 
    {
        // 使用了TaskCreationOptions.AttachedToParent 将这个Task和父Task关联, 当这个Task没有结束时  父Task 状态为 WaitingForChildrenToComplete
        var innerTask = Task.Factory.StartNew(() => TaskMethod("Second Task",5), TaskCreationOptions.AttachedToParent);

        innerTask.ContinueWith(t => TaskMethod("Thrid Task", 2), TaskContinuationOptions.AttachedToParent);

        return TaskMethod("First Task",2);
    });

    firstTask.Start();

    // 检查firstTask线程状态  根据上面的分析 首先是  Running -> WatingForChildrenToComplete -> RanToCompletion
    while (! firstTask.IsCompleted)
    {
        WriteLine(firstTask.Status);

        Sleep(TimeSpan.FromSeconds(0.5));
    }

    WriteLine(firstTask.Status);

    Console.ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    WriteLine($"任务 {name} 正在运行,线程池线程 Id {CurrentThread.ManagedThreadId},是否为线程池线程: {CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(seconds));

    return 42 * seconds;
}

运维结果如下图所示,与预期结果一律。个中使用了task.Status来打字与印刷职分运营的情景,对于task.Status的动静具体意思如下表所示。

成员名称 说明
Canceled 该任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;或者在该任务开始执行之前,已向该任务的 CancellationToken 发出了信号。 有关详细信息,请参阅任务取消
Created 该任务已初始化,但尚未被计划。
Faulted 由于未处理异常的原因而完成的任务。
RanToCompletion 已成功完成执行的任务。
Running 该任务正在运行,但尚未完成。
WaitingForActivation 该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。
WaitingForChildrenToComplete 该任务已完成执行,正在隐式等待附加的子任务完成。
WaitingToRun 该任务已被计划执行,但尚未开始执行。

澳门新萄京官方网站 23

线程池相当于线程和用户之间的二个抽象层,向程序员隐藏了应用线程的底细,使得程序猿专心管理程序逻辑,而不是种种线程难点。

一.伍 将APM形式转变为天职

在目前的章节中,介绍了基于IAsyncResult接口实现了BeginXXXX/EndXXXX主意的就叫APM方式。APM方式尤其古老,那么怎么着将它转换为TAP形式呢?对于广泛的两种APM格局异步职分,大家一般选用选拔Task.Factory.FromAsync()办法来贯彻将APM模式转换为TAP模式

示范代码如下所示,比较轻易不作过多介绍。

static void Main(string[] args)
{
    int threadId;
    AsynchronousTask d = Test;
    IncompatibleAsychronousTask e = Test;

    // 使用 Task.Factory.FromAsync方法 转换为Task
    WriteLine("Option 1");
    Task<string> task = Task<string>.Factory.FromAsync(d.BeginInvoke("异步任务线程", CallBack, "委托异步调用"), d.EndInvoke);

    task.ContinueWith(t => WriteLine($"回调函数执行完毕,现在运行续接函数!结果:{t.Result}"));

    while (!task.IsCompleted)
    {
        WriteLine(task.Status);
        Sleep(TimeSpan.FromSeconds(0.5));
    }
    WriteLine(task.Status);
    Sleep(TimeSpan.FromSeconds(1));

    WriteLine("----------------------------------------------");
    WriteLine();

    // 使用 Task.Factory.FromAsync重载方法 转换为Task
    WriteLine("Option 2");

    task = Task<string>.Factory.FromAsync(d.BeginInvoke,d.EndInvoke,"异步任务线程","委托异步调用");

    task.ContinueWith(t => WriteLine($"任务完成,现在运行续接函数!结果:{t.Result}"));

    while (!task.IsCompleted)
    {
        WriteLine(task.Status);
        Sleep(TimeSpan.FromSeconds(0.5));
    }
    WriteLine(task.Status);
    Sleep(TimeSpan.FromSeconds(1));

    WriteLine("----------------------------------------------");
    WriteLine();

    // 同样可以使用 FromAsync方法 将 BeginInvoke 转换为 IAsyncResult 最后转换为 Task
    WriteLine("Option 3");

    IAsyncResult ar = e.BeginInvoke(out threadId, CallBack, "委托异步调用");
    task = Task<string>.Factory.FromAsync(ar, _ => e.EndInvoke(out threadId, ar));

    task.ContinueWith(t => WriteLine($"任务完成,现在运行续接函数!结果:{t.Result},线程Id {threadId}"));

    while (!task.IsCompleted)
    {
        WriteLine(task.Status);
        Sleep(TimeSpan.FromSeconds(0.5));
    }
    WriteLine(task.Status);

    ReadLine();
}

delegate string AsynchronousTask(string threadName);
delegate string IncompatibleAsychronousTask(out int threadId);

static void CallBack(IAsyncResult ar)
{
    WriteLine("开始运行回调函数...");
    WriteLine($"传递给回调函数的状态{ar.AsyncState}");
    WriteLine($"是否为线程池线程:{CurrentThread.IsThreadPoolThread}");
    WriteLine($"线程池工作线程Id:{CurrentThread.ManagedThreadId}");
}

static string Test(string threadName)
{
    WriteLine("开始运行...");
    WriteLine($"是否为线程池线程:{CurrentThread.IsThreadPoolThread}");
    Sleep(TimeSpan.FromSeconds(2));

    CurrentThread.Name = threadName;
    return $"线程名:{CurrentThread.Name}";
}

static string Test(out int threadId)
{
    WriteLine("开始运行...");
    WriteLine($"是否为线程池线程:{CurrentThread.IsThreadPoolThread}");
    Sleep(TimeSpan.FromSeconds(2));

    threadId = CurrentThread.ManagedThreadId;
    return $"线程池线程工作Id是:{threadId}";
}

运行结果如下图所示。

澳门新萄京官方网站 24

只是使用线程池也很复杂。有多少个难点存在:

一.6 将EAP方式调换为职务

在上几章中有关联,通过BackgroundWorker类经过事件的不二法门贯彻的异步,大家叫它EAP情势。那么怎么样将EAP格局转变为天职吗?很轻便,我们只必要通过TaskCompletionSource类,就能够将EAP格局转变为职分。

演示代码如下所示。

static void Main(string[] args)
{
    var tcs = new TaskCompletionSource<int>();

    var worker = new BackgroundWorker();
    worker.DoWork  = (sender, eventArgs) =>
    {
        eventArgs.Result = TaskMethod("后台工作", 5);
    };

    // 通过此方法 将EAP模式转换为 任务
    worker.RunWorkerCompleted  = (sender, eventArgs) =>
    {
        if (eventArgs.Error != null)
        {
            tcs.SetException(eventArgs.Error);
        }
        else if (eventArgs.Cancelled)
        {
            tcs.SetCanceled();
        }
        else
        {
            tcs.SetResult((int)eventArgs.Result);
        }
    };

    worker.RunWorkerAsync();

    // 调用结果
    int result = tcs.Task.Result;

    WriteLine($"结果是:{result}");

    ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    WriteLine($"任务{name}运行在线程{CurrentThread.ManagedThreadId}上. 是否为线程池线程{CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(seconds));

    return 42 * seconds;
}

运营结果如下图所示。

澳门新萄京官方网站 25

壹获取线程池中的职业线程的结果比较难

壹.七 实现打消选项

在TAP格局中,落成撤销选项和事先的异步方式同样,皆以应用CancellationToken来达成,可是区别的是Task构造函数允许传入一个CancellationToken,从而在任务实际运维从前裁撤它。

演示代码如下所示。

static void Main(string[] args)
{
    var cts = new CancellationTokenSource();
    // new Task时  可以传入一个 CancellationToken对象  可以在线程创建时  变取消任务
    var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token);
    WriteLine(longTask.Status);
    cts.Cancel();
    WriteLine(longTask.Status);
    WriteLine("第一个任务在运行前被取消.");

    // 同样的 可以通过CancellationToken对象 取消正在运行的任务
    cts = new CancellationTokenSource();
    longTask = new Task<int>(() => TaskMethod("Task 2", 10, cts.Token), cts.Token);
    longTask.Start();

    for (int i = 0; i < 5; i  )
    {
        Sleep(TimeSpan.FromSeconds(0.5));
        WriteLine(longTask.Status);
    }
    cts.Cancel();
    for (int i = 0; i < 5; i  )
    {
        Sleep(TimeSpan.FromSeconds(0.5));
        WriteLine(longTask.Status);
    }

    WriteLine($"这个任务已完成,结果为{longTask.Result}");

    ReadLine();
}

static int TaskMethod(string name, int seconds, CancellationToken token)
{
    WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}");

    for (int i = 0; i < seconds; i  )
    {
        Sleep(TimeSpan.FromSeconds(1));
        if (token.IsCancellationRequested)
        {
            return -1;
        }
    }

    return 42 * seconds;
}

运作结果如下图所示,这里要求专注的是,假若是在职分实行在此之前撤销了任务,那么它的最后状态是Canceled。假使是在实行进程中打消职分,那么它的状态是RanCompletion

澳门新萄京官方网站 26

二落成线程池中央银行事线程实践的时序难题

壹.八 管理职分中的极度

在职分中,管理卓殊和其余异步方式管理万分类似,假使能在所爆发相当的线程中管理,那么毫无在其它地方管理。可是对于一些不可预期的不胜,那么能够经过三种艺术来拍卖。

可以经过拜访task.Result品质来管理十分,因为访问那一个特性的Get方法会使近期线程等待直到该职分成功,并将那四个传播给当下线程,那样就能够通过try catch语句块来捕获相当。其余利用task.GetAwaiter().GetResult()办法和第使用task.Result好像,一样能够捕获卓殊。假设是要捕获七个职务中的格外错误,那么能够经过ContinueWith()办法来管理。

切切实实哪些促成,演示代码如下所示。

static void Main(string[] args)
{
    Task<int> task;
    // 在主线程中调用 task.Result task中的异常信息会直接抛出到 主线程中
    try
    {
        task = Task.Run(() => TaskMethod("Task 1", 2));
        int result = task.Result;
        WriteLine($"结果为: {result}");
    }
    catch (Exception ex)
    {
        WriteLine($"异常被捕捉:{ex.Message}");
    }
    WriteLine("------------------------------------------------");
    WriteLine();

    // 同上 只是访问Result的方式不同
    try
    {
        task = Task.Run(() => TaskMethod("Task 2", 2));
        int result = task.GetAwaiter().GetResult();
        WriteLine($"结果为:{result}");
    }
    catch (Exception ex)
    {
        WriteLine($"异常被捕捉: {ex.Message}");
    }
    WriteLine("----------------------------------------------");
    WriteLine();

    var t1 = new Task<int>(() => TaskMethod("Task 3", 3));
    var t2 = new Task<int>(() => TaskMethod("Task 4", 4));

    var complexTask = Task.WhenAll(t1, t2);
    // 通过ContinueWith TaskContinuationOptions.OnlyOnFaulted的方式 如果task出现异常 那么才会执行该方法
    var exceptionHandler = complexTask.ContinueWith(t => {
        WriteLine($"异常被捕捉:{t.Exception.Message}");
        foreach (var ex in t.Exception.InnerExceptions)
        {
            WriteLine($"-------------------------- {ex.Message}");
        }
    },TaskContinuationOptions.OnlyOnFaulted);

    t1.Start();
    t2.Start();

    ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(seconds));
    // 人为抛出一个异常
    throw new Exception("Boom!");
    return 42 * seconds;
}

运转结果如下所示,须求注意的是,要是在ContinueWith()措施中抓获多少个职分爆发的老大,那么它的老大类型是AggregateException,具体的不行音信包涵在InnerExceptions个中,要留意和InnerException区分。

澳门新萄京官方网站 27

综上,大家在第3章中提过的异步编制程序模型和遵照事件的异步编制程序模型,那一个形式使得获取结果尤其轻松,传播也更自在,不过在拓展五个异步操作结合的时候,还必要编写制定多量的代码。对于第2个难题.NET 四.0提议了三个新的关于异步操作的API。叫做任务并行库(Task Parallel Library 简称 TPL)。

一.九 相互运营职分

本节中驷不如舌介绍了多少个法子的施用,几个是伺机组中全体职责都试行完结的Task.WhenAll()办法,另2个是倘诺组中一个主意推行落成都实行的Task.WhenAny()方法。

切实采取,如下演示代码所示。

static void Main(string[] args)
{
    // 第一种方式 通过Task.WhenAll 等待所有任务运行完成
    var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
    var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));

    // 当firstTask 和 secondTask 运行完成后 才执行 whenAllTask的ContinueWith
    var whenAllTask = Task.WhenAll(firstTask, secondTask);
    whenAllTask.ContinueWith(t => WriteLine($"第一个任务答案为{t.Result[0]},第二个任务答案为{t.Result[1]}"), TaskContinuationOptions.OnlyOnRanToCompletion);

    firstTask.Start();
    secondTask.Start();

    Sleep(TimeSpan.FromSeconds(4));

    // 使用WhenAny方法  只要列表中有一个任务完成 那么该方法就会取出那个完成的任务
    var tasks = new List<Task<int>>();
    for (int i = 0; i < 4; i  )
    {
        int counter = 1;
        var task = new Task<int>(() => TaskMethod($"Task {counter}",counter));
        tasks.Add(task);
        task.Start();
    }

    while (tasks.Count > 0)
    {
        var completedTask = Task.WhenAny(tasks).Result;
        tasks.Remove(completedTask);
        WriteLine($"一个任务已经完成,结果为 {completedTask.Result}");
    }

    ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    WriteLine($"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}");

    Sleep(TimeSpan.FromSeconds(seconds));
    return 42 * seconds;
}

运维结果如下图所示。

澳门新萄京官方网站 28

 

一.拾 使用TaskScheduler配置职务推行

Task中,肩负职责调治是TaskScheduler目的,FCL提供了七个派生自TaskScheduler的类型:线程池任务调整器(Thread Pool Task Scheduler)共同上下文职责调节器(Synchronization Scheduler)。私下认可景况下具备应用程序都使用线程池职分调治器,不过在UI组件中,不使用线程池中的线程,防止跨线程更新UI,需求选拔同步上下文任务调整器。能够透超过实际行TaskSchedulerFromCurrentSynchronizationContext()静态方法来博取对联合上下文职分调节器的引用。

示范程序如下所示,为了延时一齐上下文任务调解器,大家此次利用WPF来创造项目。

MainWindow.xaml 代码如下所示。

<Window x:Class="Recipe9.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Recipe9"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TextBlock Name="ContentTextBlock" HorizontalAlignment="Left" Margin="44,134,0,0" VerticalAlignment="Top" Width="425" Height="40"/>
        <Button Content="Sync" HorizontalAlignment="Left" Margin="45,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonSync_Click"/>
        <Button Content="Async" HorizontalAlignment="Left" Margin="165,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonAsync_Click"/>
        <Button Content="Async OK" HorizontalAlignment="Left" Margin="285,190,0,0" VerticalAlignment="Top" Width="75" Click="ButtonAsyncOK_Click"/>
    </Grid>
</Window>

MainWindow.xaml.cs 代码如下所示。

/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    // 同步执行 计算密集任务 导致UI线程阻塞
    private void ButtonSync_Click(object sender, RoutedEventArgs e)
    {
        ContentTextBlock.Text = string.Empty;

        try
        {
            string result = TaskMethod().Result;
            ContentTextBlock.Text = result;
        }
        catch (Exception ex)
        {
            ContentTextBlock.Text = ex.InnerException.Message;
        }
    }

    // 异步的方式来执行 计算密集任务 UI线程不会阻塞 但是 不能跨线程更新UI 所以会有异常
    private void ButtonAsync_Click(object sender, RoutedEventArgs e)
    {
        ContentTextBlock.Text = string.Empty;
        Mouse.OverrideCursor = Cursors.Wait;

        Task<string> task = TaskMethod();
        task.ContinueWith(t => {
            ContentTextBlock.Text = t.Exception.InnerException.Message;
            Mouse.OverrideCursor = null;
        }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
    }

    // 通过 异步 和 FromCurrentSynchronizationContext方法 创建了线程同步的上下文  没有跨线程更新UI 
    private void ButtonAsyncOK_Click(object sender, RoutedEventArgs e)
    {
        ContentTextBlock.Text = string.Empty;
        Mouse.OverrideCursor = Cursors.Wait;
        Task<string> task = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext());

        task.ContinueWith(t => Mouse.OverrideCursor = null,
            CancellationToken.None,
            TaskContinuationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
    }

    Task<string> TaskMethod()
    {
        return TaskMethod(TaskScheduler.Default);
    }

    Task<string> TaskMethod(TaskScheduler scheduler)
    {
        Task delay = Task.Delay(TimeSpan.FromSeconds(5));

        return delay.ContinueWith(t =>
        {
            string str = $"任务运行在{CurrentThread.ManagedThreadId}上. 是否为线程池线程:{CurrentThread.IsThreadPoolThread}";

            Console.WriteLine(str);

            ContentTextBlock.Text = str;
            return str;
        }, scheduler);
    }
}

运作结果如下所示,从左至右依次单击开关,前三个按钮将会掀起这些。
澳门新萄京官方网站 29

切切实实信息如下所示。

澳门新萄京官方网站 30

TPL可以看成线程池之上的又二个抽象层,其对程序猿隐藏了与线程池交互的底层代码,并提供了更有利的细粒度的API。

参考书籍

正文首要参照了以下几本书,在此对那个我表示真心的谢谢,谢谢你们为.Net的发扬所做的进献!

  1. 《CLR via C#》
  2. 《C# in Depth Third Edition》
  3. 《Essential C# 6.0》
  4. 《Multithreading with C# Cookbook Second Edition》
  5. 《C#102线程编制程序实战》

源码下载点击链接 示范源码下载

TPL的基本概念是天职。贰个职分代表了贰个异步操作,该操作可以利用三种主意运营,能够采纳或不选用独立线程运行。

笔者水平有限,假若不当招待各位讨论指正!

自然想趁待业时期的大运读完《Multithreading with C# Cookbook Second 艾德ition》那本书,并且享受做的连锁笔记;不过出于作者近期专门的学业规划和人身原因,恐怕近年来都未曾时间来更新这一个连串,没办法做到几天壹更。请大家多多原谅!不过小编一定会将以此体系全体更新完毕的!谢谢大家的援助!

一个职分能够有三种格局和别的义务组合起来。举例,能够而且进行五个任务,等待全体任务成功,然后运维三个职务对此前全部的职分结果开始展览部分计量。TPL与此前的方式相比较,其中二个关键优势是其抱有用于组合义务的便利的API。

处理义务中的非凡结果也有三种方法。二个职务能够由种种任务组成,这个职责也得以有独家的子职分,所以有三个AggregateException的定义。那种尤其能够捕获底层职分之中的有着尤其,并允许单独处理那个非常。

C#5.0中能够利用await和async关键词以平滑的,舒服的主意实行操作职务。

 

四.2 创造职务

开创任务有两种方法:

壹.直接创制任务实例,通超过实际例方法Start方法来运维职务

二.运用静态方法Task.Run和Task.Factory.StartNew来创制职责,两者都无需突显的调用start方法运营任务,差别在于前者是继任者的一种快速格局,后者能够利用附加的选项。

例:
1     class Program
2     {
3         static void Main(string[] args)
4         {
5             //第一种直接创建任务实例,需要用start方法来启动任务
6             var t1 = new Task(() => TaskMethod("Task 1"));
7             var t2 = new Task(() => TaskMethod("Task 2"));
8             t2.Start();
9             t1.Start();
10           //第二种通过Task.Factory.StartNew来创建任务
11           //这里Run方法只是Task.Factory.StartNew的一个快捷方式,Task.Factory.StartNew可以添加附加选项
12           Task.Run(() => TaskMethod("Task 3"));
13           Task.Factory.StartNew(() => TaskMethod("Task 4"));
14           //我们标记了该任务是长时间任务,结果该任务没有使用线程池,而是在单独的线程中运行
15           Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
16           Thread.Sleep(TimeSpan.FromSeconds(1));
17         }
18 
19         static void TaskMethod(string name)
20         {
21             Console.WriteLine(
22                                 "Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
23                                  name,
24                                 Thread.CurrentThread.ManagedThreadId, 
25                                 Thread.CurrentThread.IsThreadPoolThread);
26         }
27   }

澳门新萄京官方网站 31

※由于尚未对任务的时序做拍卖,所未来往实施每贰回都可能不相同。

※Task5接纳的是单身线程的章程来运营,不过依照运维该任务的此时此刻的职务调整程序(task scheduler),运汇兑势恐怕会不相同。

 

四.三运用职责实践基本的操作

首要介绍怎么样从任务中获得结果。

1     class Program
2     {
3         static void Main(string[] args)
4         {
5              //启动主线程
6              TaskMethod("Main Thread Task");
7              //创建一个任务Task1,进行线程的同步
8              Task<int> task = CreateTask("Task 1");
9              task.Start();
10             //阻塞主线程,直到线程执行完成
11             int result = task.Result;
12             Console.WriteLine("Result is: {0}", result);
13 
14             //创建Taks2,使用RunSynchronously()方法进行同步
15             task = CreateTask("Task 2");
16             task.RunSynchronously();
17             result = task.Result;
18             Console.WriteLine("Result is: {0}", result);
19 
20             //创建Task3,此时不进行主线程的阻塞
21             task = CreateTask("Task 3");
22             Console.WriteLine(task.Status);
23             task.Start();
24 
25             //循环打印task的状态,直到任务完成
26             while (!task.IsCompleted)
27             {
28                 Console.WriteLine(task.Status);
29                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
30             } 
31             
32             Console.WriteLine(task.Status);
33             result = task.Result;
34             Console.WriteLine("Result is: {0}", result);
35         }
36 
37         //创建一个新任务
38         static Task<int> CreateTask(string name)
39         {
40             return new Task<int>(() => TaskMethod(name));
41         }
42 
43         //任务需要处理的方法
44         static int TaskMethod(string name)
45         {
46             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
47             name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
48             Thread.Sleep(TimeSpan.FromSeconds(2));
49             return 42;
50         }
51    }

实施结果:

澳门新萄京官方网站 32

 

4.4 组合职责

此地小编会学习到哪边将义务张开整合,以及老爹和儿子职分之间的施行。废话不说,有码

实例1:

1     class Program
2     {
3         static void Main(string[] args)
4         {
5             //打印主线程
6             TaskMethod("Main Task", 1);
7             //创建两个任务
8             var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
9             var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
10 
11             //设置firstTask的后续操作
12             firstTask.ContinueWith(
13                 t => Console.WriteLine("The first answer is {0}. Thread id {1}, is thread pool thread: {2}",
14                     t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread),
15                 TaskContinuationOptions.OnlyOnRanToCompletion);
16 
17              //启动两个任务
18             firstTask.Start();
19             secondTask.Start();
20             //延时4秒,足够两个任务完成的时间※↓这句是关键
21             Thread.Sleep(TimeSpan.FromSeconds(4));
22 
23             //为secondTask设置一个后续操作,TaskContinuationOptions.ExecuteSynchronously尝试同步方式执行后续操作
24             Task continuation = secondTask.ContinueWith(
25                 t => Console.WriteLine("The second answer is {0}. Thread id {1}, is thread pool thread: {2}",
26                     t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread),
27                 TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);
28 
29             //为之前的后续操作也定义一个后续操作,这里使用了C#5.0的方法GetAwaiter().OnCompleted()
30             continuation.GetAwaiter().OnCompleted(
31                 () => Console.WriteLine("Continuation Task Completed! Thread id {0}, is thread pool thread: {1}",
32                     Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread));
33 
34             Thread.Sleep(TimeSpan.FromSeconds(2));
35             Console.WriteLine();
36 
37             Thread.Sleep(TimeSpan.FromSeconds(10));
38         }
39 
40         static int TaskMethod(string name, int seconds)
41         {
42             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
43                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
44             Thread.Sleep(TimeSpan.FromSeconds(seconds));
45             return 42 * seconds;
46         }
47  }

澳门新萄京官方网站 33

此地我们看来secondTask的两次三番操作未有选拔到线程池,为何吧?

解释:由地点的代码大家见到,使用了TaskContinuationOptions.ExecuteSynchronously尝试同步格局实践后续操作,借使继续操作时间十分长暂,使用方面包车型大巴点子尤其有效用的,因为放置在主线程实行运行要比放置在线程池中运作要快,那怎么会产出那样的景色吗,正是上边标记的延时期码的功绩,那段延时期码使得SecondTask后续操作正好获得了目前职务执行的结果。未来自己把  Thread.Sleep(提姆eSpan.FromSeconds(4));注释掉再试一下,结果如下:

澳门新萄京官方网站 34

以为就如客栈打饭,五个人用餐,A帮B打饭。

率先种是:A打完饭后,发掘B刚来,就一向把饭给了B,然后B直接吃了

第二种是:A打饭的时候,B正好也来了,于是多少人一同站队,A打完饭后再把饭给了B

澳门新萄京官方网站, 

例2:演示了弹指间老爹和儿子任务之间的涉嫌。

1 class Program
2     {
3         static void Main(string[] args)
4         {
5              //创建一个父任务
6              var firstTask = new Task<int>(() =>
7             {
8                 //创建一个子任务,使用TaskCreationOptions.AttachedToParent来标识
9                 var innerTask = Task.Factory.StartNew(
10                                         () => TaskMethod("Second Task", 5), 
11                                         TaskCreationOptions.AttachedToParent);
12               //创建一个子任务的后续操作,该后续操作也会影响父任务
13                innerTask.ContinueWith(
14                                         t => TaskMethod("Third Task", 2), 
15                                         TaskContinuationOptions.AttachedToParent);
16                 return TaskMethod("First Task", 2);
17             });
18 
19             //启动任务
20             firstTask.Start();
21 
22             //循环打印任务的状态
23             while (!firstTask.IsCompleted)
24             {
25                 Console.WriteLine(firstTask.Status);
26                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
27             }
28             Console.WriteLine(firstTask.Status);
29 
30             Thread.Sleep(TimeSpan.FromSeconds(10));
31         }
32 
33         static int TaskMethod(string name, int seconds)
34         {
35             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
36                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
37             Thread.Sleep(TimeSpan.FromSeconds(seconds));
38             return 42 * seconds;
39         }

澳门新萄京官方网站 35

上边结果展现,父职分必须等待全体的子任务到位手艺达成,不过看不出来他们是同步照旧异步执行的。因为从First Task和Sencod Task它们之间的运转时序上也看不出来他们是阿爸实行完了再试行的子任务,所以笔者认为把父任务的岁月调长一点,这回自家让父职分推行拾s

修改:

   return TaskMethod("First Task", 2);  →   return TaskMethod("First Task", 10);

结果如下

澳门新萄京官方网站 36

那回显得的都以firstTask的Running状态,所以理应能一定爸爸和儿子之间私下认可景况下也是异步执行的。因为父职分必供给等子职务全甘休本领不辱职分。

 

 

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站:中档的二10拾二线程_职务

关键词: