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

澳门新萄京官方网站:异步编程之基于任务的异

2019-06-01 作者:www.8455.com   |   浏览(195)

上一篇轻松讲明了 线程和线程池以及上下文切换。创设线程代价高昂,暗中认可各样线程都要占用大批量虚拟内部存款和储蓄器1M。更实惠的做法使用线程池,重复利用线程。在.NET四.0中引进了TPL职分并行库,你可以在将精力聚集于程序要做到的职业,同期最大程度地抓牢代码的习性。在C#5.0中引进了async 和 await关键字,基于职责的异步情势(TAP),所以通晓Task对前边学习异步操作会简单些。 

 IO操作的MDA(Direct memory access)形式:直接待上访问内部存款和储蓄器,是1种不通过CPU而直白进行内部存储器数据存款和储蓄的数据交换方式,差非常少能够不损耗CPU的财富;
 CL福特Explorer所提供的异步编程模型就是丰硕利用硬件的DMA功用来刑释CPU的下压力;使用线程池实行保管,异步将专门的学问移交给线程池中的有个别专门的学业线程来变成,直到异步达成,异步才会透过回调的点子公告线程池,让CLPRADO响应异步完成;

该文讲了基于任务的编制程序,这里再详尽介绍一下。
1.持续职分

C#异步编制程序之基于职分的异步格局,


一.三番五次任务

  

private async static void CallerWithAsync()
    {
      string result = await GreetingAsync("Stephanie");
      Console.WriteLine(result);
    }

    static Task<string> GreetingAsync(string name)
    {
      return Task.Run<string>(() =>
        {
            Thread.Sleep(10000);
            return name;
        });
    }

    GreetingAsync方法返回一个Task<string>对象。该Task<string>对象包含任务创建的信息,并保存到任务完成。Task类的ContinueWith方法定义了任务完成后就调用的代码。
        private static void CallerWithContinuationTask()
        {

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
            });


        }

  由于不行使await,线程不会在章程中伺机,会实行完CallerWithContinuationTask()的代码。不会再ContinueWith这里等待,所以必要三个前台线程,不然会停业所以线程。

二.联手上下文

  CallerWithAsync和CallerWithContinuationTask方法在情势的例外品级选择了差异的线程。

  

static Task<string> GreetingAsync(string name)
        {
          return Task.Run<string>(() =>
            {
                Thread.Sleep(10000);
              Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
              return name;
            });
        }
        private async static void CallerWithAsync()
        {
          Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
          string result = await GreetingAsync("Stephanie");
          Console.WriteLine(result);
          Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
        }

        private static void CallerWithContinuationTask()
        {
          Console.WriteLine("started CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
              Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
            });


        }

 

  使用async和await关键字,当await达成后,无需实行其它管理,就会访问UI线程。默许情状下,生成的代码就能够把线程转变来具有共同上下文的线程中。调用异步方法的线程分配给了一齐上下文,await完结今后将继续推行。

假如不选用同样的同台上下文,必须调用Task类的ConfigureAwait(false).举例,3个WPF应用程序,其await后边的代码未有别的用到UI成分的代码。在这种景况下,制止切换来一齐上下文种施行的越来越快。
  string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);

叁.使用七个异步方法

  在二个异步方法里,能够调用一个或几个异步方法。怎样编写代码,取决于四个异步方法的结果是不是取决于另三个异步方法。
  壹.按顺序调用异步方法

  上边包车型地铁事例,第第三个异步方法重视于首个异步方法的结果,await关键字就很有用。
  private async static void MultipleAsyncMethods()
  {
    string s1 = await GreetingAsync("Stephanie");
    string s2 = await GreetingAsync(s1);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", s1, s2);
  }

  2.应用组合器

  假如第三个异步方法独立于第3个,每种异步方法能够都不选择await,而是把各类异步方法的归来结果赋值给Task变量,就能够运作的更快。
  private async static void MultipleAsyncMethodsWithCombinators1()
  {
    Task<string> t1 = GreetingAsync("Stephanie");
    Task<string> t2 = GreetingAsync("Matthias");
    await Task.WhenAll(t1, t2);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", t1.Result, t2.Result);
  }

  Task.WhenAll组合器基本上能用三个壹律类型的参数,并回到同1品种的值。
  Task.WhenAll是在有着传入方法的职分都成功了才回来Task。
  WhenAny是在中间多少个传诵方法的天职成功了就回到。

  Task.WhenAll定义了多少个重载版本。假使全体的任务回到一样的品种,那么该类型的数组可用于await重回的结果。
  string[] result = await Task.WhenAll(t1, t2);

肆.调换异步情势

  
  并非全部的.NET Framework类在.NET 肆.5中都引入了新的异步方法。还会有众多类只提供类BeginXXX和EndXXX方法的异步情势,能够选用TaskFactory类的FromAsync方法,它能够把利用异步格局的不二等秘书籍转变为基于义务的异步情势的格局。   

/创建一个委托,并引用同步方法Greeting
        private static Func<string, string> greetingInvoker = Greeting;


        static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
        {
          return greetingInvoker.BeginInvoke(name, callback, state);
        }

        static string EndGreeting(IAsyncResult ar)
        {
          return greetingInvoker.EndInvoke(ar);
        }

        //FromAsync方法的前两个参数是委托类型,传入BeginGreeting, EndGreeting的地址。后两个参数是输入的参数和对象状态参数。
        private static async void ConvertingAsyncPattern()
        {
          string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
          Console.WriteLine(r);
        }

 

5.错误管理

  假若调用异步方法未有等待,将异步方法放在try/catch中,就不抓获不到足够。   

private static void DontHandle()
        {
          try
          {
            ThrowAfter(200, "first");
            // exception is not caught because this method is finished before the exception is thrown
          }
          catch (Exception ex)
          {
            Console.WriteLine(ex.Message);
          }
        }

        static async Task ThrowAfter(int ms, string message)
        {
            Console.Write("xxx");
          await Task.Delay(ms);
          throw new Exception(message);
        }

  DontHandle方法调用ThrowAfter后,不会在该处等待,会继续实践,不再保持对ThrowAfter方法的引用。

  注意:重临void的异步方法永世不会等待.异步方法最棒重临二个Task类型。

  一.异步方法的万分管理
  使用await关键字,将其放在在try/catch中   

private static async void HandleOneError()
        {
          try
          {
            await ThrowAfter(2000, "first");
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }

 

  二.多个异步方法的丰盛管理

  借使根据下边的代码,第1个13分将不会抛出。因为第4个要命已经抛出,直接调到catch块内了。   

private static async void StartTwoTasks()
        {
          try
          {
            await ThrowAfter(2000, "first");
            await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }

  使用Task.WhenAll,不管职责是或不是抛出万分,都会等到八个义务到位。所以会抛出八个可怜。

  不过,只可以看见传递给Task.WhenAll方法的率先个职责的老大音讯,即使第二个可怜会抛出,但不会显得:   

private async static void StartTwoTasksParallel()
            {
              Task t1 = null;
              Task t2 = null;
              try
              {
                t1 = ThrowAfter(2000, "first");
                 t2 = ThrowAfter(1000, "second");
                await Task.WhenAll(t1, t2);
              }
              catch (Exception ex)
              {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine("handled {0}", ex.Message);
              }
            }

  3.运用AggregateException音讯重返展现分外

  将Task.WhenAll再次回到的结果写到2个Task变量中,catch语句只检索到第三个职责的相当,但能够访问外部任务taskResult的Exception属性。Exception属性是AggregateException类型。那么些特别类型定义了InnerExceptions属性,它包含了等候中的全数特别的列表。   

private static async void ShowAggregatedException()
        {
          Task taskResult = null;
          try
          {
            Task t1 = ThrowAfter(2000, "first");
            Task t2 = ThrowAfter(1000, "second");
            await (taskResult = Task.WhenAll(t1, t2));
          }
          catch (Exception ex)
          {
            // just display the exception information of the first task that is awaited within WhenAll
            Console.WriteLine("handled {0}", ex.Message);
            foreach (var ex1 in taskResult.Exception.InnerExceptions)
            {
              Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
            }
          }
        }

陆.裁撤异步方法
  如若后台任务恐怕运营十分短日子,就恐怕用的撤消职务。

  撤消框架基于帮忙行为,不是强制性的。三个运行时刻十分短的职务急需检查自身是或不是被收回,在这种气象下,它的劳作便是清理全部已张开的能源,并终止相关专门的工作。

  撤销基于CancellationTokenSource类,该类可用来发送撤除请求。请求发送给引用CancellationToken类的天职,在这之中CancellationToken类和CancellationTokenSource相关联。   

private CancellationTokenSource cts = new CancellationTokenSource();

        //添加一个按钮,用于取消正在运行的任务。使用cts.Cancel();
         private void button5_Click(object sender, EventArgs e)
         {
             if (cts != null)
                 cts.Cancel();
         }

        private async void button4_Click(object sender, EventArgs e)
        {

            string s =  await AsyncTaskTest();
        }

        //向Task类的Run方法传递CancellationToken参数。但需要检查是否请求了取消操作。
         Task<string> AsyncTaskTest()
        {
            return Task.Run(() =>
                {
                cts.Token.ThrowIfCancellationRequested();
                    Thread.Sleep(5000);
                    return "异步完成";
                }
            , cts.Token);
        }

 

1.连续职责 pri...

该文讲了依附职分的编制程序,这里再详尽介绍一下。
壹.承袭义务

任务是包裹了以异步情势进行的劳作。当运行二个职责,调控大概立即赶回调用者,无论职分要进行稍微职业。

它是出新的一种样式,它应用 future 方式或回调(callback)机制,防止止产生不供给的线程。贰个 future(或 promise)类型代表某些就要成功的操作。在 .NET 中,新版 future 类型有Task 和Task<TResult>。 

  

  

创建Task任务

异步编制程序情势------使用委托和线程池实现的情势

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

private async static void CallerWithAsync()
    {
      string result = await GreetingAsync("Stephanie");
      Console.WriteLine(result);
    }

    static Task<string> GreetingAsync(string name)
    {
      return Task.Run<string>(() =>
        {
            Thread.Sleep(10000);
            return name;
        });
    }

    GreetingAsync方法返回一个Task<string>对象。该Task<string>对象包含任务创建的信息,并保存到任务完成。Task类的ContinueWith方法定义了任务完成后就调用的代码。
        private static void CallerWithContinuationTask()
        {

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
            });


        }
private async static void CallerWithAsync()
    {
      string result = await GreetingAsync("Stephanie");
      Console.WriteLine(result);
    }

    static Task<string> GreetingAsync(string name)
    {
      return Task.Run<string>(() =>
        {
            Thread.Sleep(10000);
            return name;
        });
    }

    GreetingAsync方法返回一个Task<string>对象。该Task<string>对象包含任务创建的信息,并保存到任务完成。Task类的ContinueWith方法定义了任务完成后就调用的代码。
        private static void CallerWithContinuationTask()
        {

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
            });


        }

 有二种创立形式

APM

         使用IAsyncResult设计形式的异步操作是由此名称叫 BeginXXX 和 EndXXX 的八个法子来促成,那四个法子分别指早先和得了异步操作。该情势允许用越来越少的CPU能源(线程)去做越多的操作,.NET Framework大多类也促成了该情势,同时大家也足以自定义类来落到实处该格局(约等于在自定义的类中贯彻重返类型为IAsyncResult接口的BeginXXX方法和承受IAsyncResult包容类型作为唯壹参数的EndXXX方法),其余事委员会托项目也定义了BeginInvoke和EndInvoke方法。举例,FileStream类提供BeginRead和EndRead方法来从文件异步读取字节。那五个方法达成了 Read 方法的异步版本。

调用 BeginXXX 后,应用程序能够继续在调用线程上推行命令,同一时候异步操作在另3个线程上推行(假诺有重返值还应调用 EndXXX竣事异步操作,并向该措施传递BeginXXX 方法再次来到的IAsyncResult对象,得到操作的返回值)。

 澳门新萄京官方网站 1

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

走访异步操作的结果,APM提供了八种方式:

一.在调用BeginXXX方法的线程上调用EndXXX方法来获得异步操作的结果;可是这种情势会卡住调用线程,在知情操作完结之后调用线程技能继续运维。

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

叁.IAsyncResult的AsyncWaitHandle属性达成越来越灵敏的等待逻辑,调用该属性WaitOne()方法来使二个线程阻塞并听候操作落成;再调用EndXXX方法来获得操作的结果。WaitHandle.WaitOne()能够内定最长的等候时间,如超时再次来到false;

四. 在调用BeginXXX方法时提供AsyncCallback委托的实例作为参数,在异步操作完结后委托会自动调用(AsyncCallback对象)钦命的法子。(首荐办法)AsyncCallback委托仅能够调用符合一定形式的措施(只有1个参数IAsyncResult,且并未有再次回到值);

澳门新萄京官方网站 2澳门新萄京官方网站 3

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

拾贰分捕获

在1块实行的主意里面普通管理特别的秘技是将或者抛出十二分的代码放到try...catch...finally里面,之所以能够捕获到,是因为发生非常的代码与调用的代码位于同三个线程。当调用贰个异步方法发生极度时,CLHummerH二会捕获并且在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分界面控件的机制(将回调方法投递到开创该控件的线程中实践)。

 澳门新萄京官方网站 4

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

a) Invoke(同步调用)先决断控件创造线程与近期线程是不是一样,一样则一向调用委托方法;不然使用Win32API的PostMessage异步试行,不过Invoke内部会调用IAsyncResult.AsyncWaitHandle等待试行到位。

b) BeginInvoke(异步调用)使用Win32API的PostMessage 异步施行,并且再次来到IAsyncResult 对象。

动用办法:回调方法中对控件检验InvokeRequired值,if true,在该回调中封送二次委托,调用控件的Invoke/ BeginInvoke方法;

 澳门新萄京官方网站 5

2.GUI(WinForm/WPF)应用程序引进了多少个线程管理模型:创立窗口的线程是不二法门能对足够窗口实行翻新的线程;在GUI线程中,平常索要转移异步操作,使GUI线程不封堵并结束响应用户输入。但是,异步操作达成时,由于是用一个线程池线程完成的,而线程池线程不能够更新UI控件。为化解这一个难题,FCL定义贰个System.Threading.SynchronizationContext(线程同步上下文)的基类,其派生对象承担将三个应用程序模型连接到它的线程管理模型。

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

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;
         }
      }
   }
}

比较三种方法其实差不太多,一个是回调内再一次卷入,1个是包裹原本的回调。可是SynchronizationContext业务层与UI分离来说的话是比较好;

  由于不利用await,线程不会在章程中等候,会试行完CallerWithContinuationTask()的代码。不会再ContinueWith这里等候,所以须求二个前台线程,否则会关闭所以线程。

  由于不选取await,线程不会在方式中等候,会进行完CallerWithContinuationTask()的代码。不会再ContinueWith这里守候,所以供给3个前台线程,不然会停业所以线程。

  • 行使task构造函数
  • task工厂类静态方法
  • 使用.NET肆.5新引进的Task.run()。

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:向那一个事件登记的方法应该包罗总括范围的代码。那些事件由3个线程池线程调用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块。

二.联合进行上下文

二.同步上下文

咱俩制造八个出口300万个三13个人字符的GUID职责分别采用两种差异格局贯彻。代码如下 constint RepeatCount = 1000000; //重复次数

TAP

.NET肆.0 中引进了新的异步编制程序模型“基于任务的异步编制程序模型(TAP)”,并且推荐大家在开拓新的二十四线程应用程序中首荐TAP,在.NET肆.5中进一步对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值,再次回到对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类实行打包;

澳门新萄京官方网站 6

当组织1个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);
        }
}

11分管理

在职责抛出的未处理极度都封装在System.AggregateException对象中。这几个目的会积存在艺术重临的Task或Task<TResult>对象中,需求通过访问Wait()、Result、Exception成员才干体察到丰富。(所以,在拜访Result从前,应先观看IsCanceled和IsFaulted属性)

倘使平昔不访问Task的Wait()、Result、Exception成员,那么您将永久注意不到这几个至极的暴发。为了扶持你检查评定到那么些未处理的丰硕,能够向TaskScheduler对象的UnobservedTaskException事件注册回调函数。每当贰个Task被垃圾回收时,假诺存在一个未曾在意到的那一个,CLCR-V的收尾器线程会引发那些事件。

可在事变回调函数中调用UnobservedTaskException伊芙ntArgs对象的SetObserved() 方法来提议已经管理好了老大,从而阻碍CLBMWX三终止线程。但是并不推荐这么做,宁愿终止进度也并非带着早已磨损的意况继续运转。

  CallerWithAsync和CallerWithContinuationTask方法在措施的不及阶段采纳了分裂的线程。

  CallerWithAsync和CallerWithContinuationTask方法在章程的两样阶段采纳了不一致的线程。

            var listGuid = new BlockingCollection<string>();

            //Action无返回值 
            Action dowork = () =>
           {
               for (var count = 0; count < RepeatCount; count  )
               {
                   listGuid.Add(Guid.NewGuid().ToString("N"));
               }
           };
            Task task1 = new Task(dowork);  //1)使用构造函数
            task1.Start();
            Task task2 = Task.Factory.StartNew(dowork); //2)Task工厂方法,直接运行,不需要在调用start()
            Task task3 = Task.Run(dowork); //3)4.5 Task.Run 是Task.Factory.StartNew简化方式;直接运行,不需要在调用start()

            Task.WaitAll(task1, task2, task3); //等待所有任务完成,相当于 thread.join()
            Console.Write($"生成数量:{listGuid.Count / 10000}万");

Async /Await

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

Install-Package Microsoft.Bcl.Async

注:asp.net 框架必供给进级.net framework框架技艺应用 async/await

假使那1个音讯是“Message : Could not load file or assembly 'System.Core, Version=二.0.5.0, Culture=neutral, PublicKeyToken=柒cec八五d柒bea77九八e, Retargetable=Yes' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x8013拾47)”,

那必要您去微软官网下载.net四.0的KB2468871补丁来安装。

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

涵盖await表明式的方法或佚名函数;

async关键字创设了2个状态机,类似于yield return语句;await关键字只可以用于有用async修饰符申明的艺术。async修饰符只好用来重回Task/Task<TResult>或void的不二秘诀。await只可以用来调用再次回到Task/Task<TResult>的方式;await会解除线程的堵塞,实现调用的任务;等待使命成功后,获取结果,然后实行await关键字背后的代码;编写翻译器会把await的表明式后的代码应用 Task.ContinueWith 打包了起来,回调时私下认可使用当前线程的五头上下文职务调整器;若是不选用同样的1块上下文,必须调用Task实例的ConfigureAwait(false)方法;

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

异步方法的注解语法与此外艺术完全平等,只是要包蕴async上下文关键字。async能够出

今天回到类型在此以前的任何地方。async修饰符在变化的代码中从未效果,也可省略不写,它鲜明宣布了你的预想,告诉编写翻译器能够积极寻找await表明式,也能够搜寻应该转换到异步调用和await表明式的块调用。

调用者和异步方法之间是透过再次来到值来通信的。异步函数的归来类型只好为:

Void 、Task、Task<TResult>;Task和Task<TResult>类型都表示3个或者还未到位的操作。 Task<TResult>承袭自Task。二者的界别是,Task<TResult>表示三个再次来到值为T类型的操作,而Task则无需发出再次来到值。在某种意义上,你能够感觉Task正是Task<void>类型;

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

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

澳门新萄京官方网站 7

 

  

  

输出澳门新萄京官方网站 8

static Task<string> GreetingAsync(string name)
        {
          return Task.Run<string>(() =>
            {
                Thread.Sleep(10000);
              Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
              return name;
            });
        }
        private async static void CallerWithAsync()
        {
          Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
          string result = await GreetingAsync("Stephanie");
          Console.WriteLine(result);
          Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
        }

        private static void CallerWithContinuationTask()
        {
          Console.WriteLine("started CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
              Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
            });


        }
static Task<string> GreetingAsync(string name)
        {
          return Task.Run<string>(() =>
            {
                Thread.Sleep(10000);
              Console.WriteLine("running greetingasync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
              return name;
            });
        }
        private async static void CallerWithAsync()
        {
          Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
          string result = await GreetingAsync("Stephanie");
          Console.WriteLine(result);
          Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
        }

        private static void CallerWithContinuationTask()
        {
          Console.WriteLine("started CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);

          var t1 = GreetingAsync("Stephanie");


          t1.ContinueWith(t =>
            {
              string result = t.Result;
              Console.WriteLine(result);
              Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
            });


        }

上述实例成立一个不曾再次来到值的任务,当然也足以由此Task<TResult> 来创立再次回到值的异步操作。

 

 

连日职责

  使用async和await关键字,当await实现后,没有必要张开任何处理,就能够访问UI线程。私下认可意况下,生成的代码就能够把线程转产生全数2头上下文的线程中。调用异步方法的线程分配给了一起上下文,await实现之后将继续施行。

  使用async和await关键字,当await实现后,无需开始展览别的管理,就可以访问UI线程。私下认可景况下,生成的代码就能够把线程转换来具有共同上下文的线程中。调用异步方法的线程分配给了协同上下文,await完结现在将继续推行。

第一个职务生成三十二位字符的Guid职务,利用重返的结果再转化成对应的ASCII码,最终ASCII码10进制的值相加。代码如下 

若是不应用同样的联手上下文,必须调用Task类的ConfigureAwait(false).比如,2个WPF应用程序,其await后边的代码未有任何用到UI成分的代码。在这种情状下,防止切换来1块儿上下文仲推行的越来越快。
  string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);

即便不行使一样的2只上下文,必须调用Task类的ConfigureAwait(false).举例,一个WPF应用程序,其await后边的代码未有其它用到UI成分的代码。在这种情状下,防止切换来壹块儿上下文仲推行的更加快。
  string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);

 //Func 
            Func<string> doWork = () =>
            {
                return Guid.NewGuid().ToString("N");
            };
            //延续任务
            var task = Task.Run(doWork).ContinueWith(async strGuid =>
            {
                var resut = await strGuid;
                var array = Encoding.ASCII.GetBytes(resut);

                int mLenght = array.Length;
                int sumResult = 0;
                for (int m = 0; m < mLenght; m  )
                {
                    sumResult  = array[m];
                }
                Console.WriteLine($"Guid对应10进制相加结果:{sumResult}");
            });

3.使用多少个异步方法

三.使用八个异步方法

输出澳门新萄京官方网站 9 

  在三个异步方法里,能够调用1个或五个异步方法。怎么样编写代码,取决于2个异步方法的结果是还是不是取决于另四个异步方法。
  一.按顺序调用异步方法

  在二个异步方法里,能够调用3个或多少个异步方法。怎么着编写代码,取决于贰个异步方法的结果是不是取决于另四个异步方法。
  一.按顺序调用异步方法

管理职务非凡

  下边包车型大巴例子,第第二个异步方法重视于第贰个异步方法的结果,await关键字就很有用。
  private async static void MultipleAsyncMethods()
  {
    string s1 = await GreetingAsync("Stephanie");
    string s2 = await GreetingAsync(s1);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", s1, s2);
  }

  下边包车型客车事例,第第一个异步方法信赖于第多个异步方法的结果,await关键字就很有用。
  private async static void MultipleAsyncMethods()
  {
    string s1 = await GreetingAsync("Stephanie");
    string s2 = await GreetingAsync(s1);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", s1, s2);
  }

手拉手代码要想捕获非常,只需在代码块上增加Try ...Catch就可以。但是异步调用不能够这么做。因为调节会立即从调用重返,然后调整会离开Try块,而那时候距离工笔者线程产生卓殊或者还恐怕有持久呢。

  二.选拔组合器

  2.运用组合器

为了管理失误的天职,3个技巧是显式创设两次三番职责作为这几个任务的“错误管理程序”。检查实验到先驱义务引发未处理的老大,职责调解器会自动调整一而再职分。不过,假诺未有这种管理程序,相同的时候在失误的任务上进行wait()(或别的试图拿走result的动作),就能够掀起一个AggregateException,示例代码如下。

  如若第四个异步方法独立于第三个,每种异步方法能够都不选拔await,而是把每一个异步方法的归来结果赋值给Task变量,就能够运维的更加快。
  private async static void MultipleAsyncMethodsWithCombinators1()
  {
    Task<string> t1 = GreetingAsync("Stephanie");
    Task<string> t2 = GreetingAsync("Matthias");
    await Task.WhenAll(t1, t2);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", t1.Result, t2.Result);
  }

  假设第一个异步方法独立于第3个,各种异步方法能够都不使用await,而是把种种异步方法的回来结果赋值给Task变量,就能运作的更加快。
  private async static void MultipleAsyncMethodsWithCombinators1()
  {
    Task<string> t1 = GreetingAsync("Stephanie");
    Task<string> t2 = GreetingAsync("Matthias");
    await Task.WhenAll(t1, t2);
    Console.WriteLine("Finished both methods.n Result 1: {0}n Result 2: {1}", t1.Result, t2.Result);
  }

  Task task = Task.Run(() =>
            {
                throw new InvalidOperationException();
            });

            try
            {
                task.Wait();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"常规erro:{ex.Message};type:{ex.GetType()}");
                AggregateException excetion = (AggregateException)ex;
                excetion.Handle(eachException =>
                {
                    Console.WriteLine($"erro:{eachException.Message}");
                    return true;
                });
            }

  Task.WhenAll组合器能够承受几个一律类型的参数,并再次来到同1品种的值。

  Task.WhenAll组合器能够承受多少个同样品种的参数,并赶回同1品种的值。

输出澳门新萄京官方网站 10

  Task.WhenAll是在装有传入方法的任务都形成了才回去Task。

  Task.WhenAll是在具有传入方法的职责都产生了才回去Task。

即便工小编线程辰月发的未管理相当是InvalidOperationException类型,但主线程捕捉的仍是1个AggregateException。由于编写翻译时不掌握工小编职责就要引发三个照旧多个极度,所以未管理的失误职责接二连三吸引四个AggregateException。

  WhenAny是在内部3个传开药方法的任务实现了就再次来到。

  WhenAny是在里头二个不知去向方法的职务成功了就回到。

  还可查看任务的Exception属性来打探出错任务的情景,那样不会促成在此时此刻线程上再也引发这个。代码如下

  Task.WhenAll定义了多少个重载版本。如若具有的职分重返同样的品类,那么该类型的数组可用于await再次回到的结果。
  string[] result = await Task.WhenAll(t1, t2);

  Task.WhenAll定义了多少个重载版本。借使全部的任务重返同样的档案的次序,那么该类型的数组可用于await重临的结果。
  string[] result = await Task.WhenAll(t1, t2);

  bool paraentTaskFaulted = false;
            Task task = new Task(() =>
            {
                throw new InvalidOperationException();
            });

            Task continuationTask = task.ContinueWith(t =>
            {

                paraentTaskFaulted = t.IsFaulted;
            }, TaskContinuationOptions.OnlyOnFaulted);

            task.Start();
            Console.Write(continuationTask.Status);
            continuationTask.Wait();
            //如果断言失败 则显示一个消息框,其中显示调用堆栈。
            Trace.Assert(paraentTaskFaulted);
            if (!task.IsFaulted)
            {
                task.Wait();
            }
            else
            {
                task.Exception.Handle(eachException =>
                {
                    Console.WriteLine($"erro:{eachException.Message}");
                    return true;
                });
            }

四.转换异步格局

四.转移异步形式

 

  讲了两种异步编制程序的情势。
  并非所有的.NET Framework类在.NET 4.5中都引进了新的异步方法。还恐怕有繁多类只提供类BeginXXX和EndXXX方法的异步形式,能够应用TaskFactory类的FromAsync方法,它能够把施用异步格局的不二等秘书诀调换为依照任务的异步形式的格局。   

  讲了二种异步编制程序的格局。
  并非全部的.NET Framework类在.NET 肆.5中都引进了新的异步方法。还应该有十分的多类只提供类BeginXXX和EndXXX方法的异步形式,能够行使TaskFactory类的FromAsync方法,它能够把利用异步形式的方式转变为依照任务的异步格局的方法。   

在意,为了获取原始任务上的未管理相当,大家使用Exception属性。结果和方面示例输出一样。

/创建一个委托,并引用同步方法Greeting
        private static Func<string, string> greetingInvoker = Greeting;


        static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
        {
          return greetingInvoker.BeginInvoke(name, callback, state);
        }

        static string EndGreeting(IAsyncResult ar)
        {
          return greetingInvoker.EndInvoke(ar);
        }

        //FromAsync方法的前两个参数是委托类型,传入BeginGreeting, EndGreeting的地址。后两个参数是输入的参数和对象状态参数。
        private static async void ConvertingAsyncPattern()
        {
          string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
          Console.WriteLine(r);
        }
/创建一个委托,并引用同步方法Greeting
        private static Func<string, string> greetingInvoker = Greeting;


        static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
        {
          return greetingInvoker.BeginInvoke(name, callback, state);
        }

        static string EndGreeting(IAsyncResult ar)
        {
          return greetingInvoker.EndInvoke(ar);
        }

        //FromAsync方法的前两个参数是委托类型,传入BeginGreeting, EndGreeting的地址。后两个参数是输入的参数和对象状态参数。
        private static async void ConvertingAsyncPattern()
        {
          string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
          Console.WriteLine(r);
        }

裁撤职务

 

 

 任务支持撤销,举个例子常用在钦定时期内的天职依旧遵照某个标准手动的吊销,辅助撤消的职分要监听2个CancellationToken对象。职务轮询它,检查是否出发了撤回请求。如下代码突显了收回请求和对请求的响应。

五.错误管理

伍.错误管理

 /// <summary>
        /// 取消任务
        /// </summary>
        public void TaskTopic5()
        {
            string stars = "*".PadRight(Console.LargestWindowWidth-1,'*');
            Console.WriteLine("push enter to exit.");
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); //向应该被取消的 System.Threading.CancellationToken 发送信号
            Task task = Task.Run(
                ()=>
                Count(cancellationTokenSource.Token,100),
                cancellationTokenSource.Token);

            Console.Read();
            cancellationTokenSource.Cancel();//按下enter键, 传达取消请求

            Console.WriteLine(stars);
            Console.WriteLine(task.IsCanceled);
            task.Wait();
            Console.WriteLine();
        }
        /// <summary>
        /// 数数
        /// </summary>
        /// <param name="token"></param>
        /// <param name="countTo"></param>
        private void Count(CancellationToken token,int countTo)
        {
            for (int count = 1; count < countTo; count  )
            {
                //监控是否取消
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("数数喊停了");
                    break;
                }

                Console.Write(count "=》");
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
            Console.WriteLine("数数结束");
        }

  若是调用异步方法未有等待,将异步方法放在try/catch中,就不抓获不到足够。   

  尽管调用异步方法未有等待,将异步方法放在try/catch中,就不抓获不到十分。   

 

private static void DontHandle()
        {
          try
          {
            ThrowAfter(200, "first");
            // exception is not caught because this method is finished before the exception is thrown
          }
          catch (Exception ex)
          {
            Console.WriteLine(ex.Message);
          }
        }

        static async Task ThrowAfter(int ms, string message)
        {
            Console.Write("xxx");
          await Task.Delay(ms);
          throw new Exception(message);
        }
private static void DontHandle()
        {
          try
          {
            ThrowAfter(200, "first");
            // exception is not caught because this method is finished before the exception is thrown
          }
          catch (Exception ex)
          {
            Console.WriteLine(ex.Message);
          }
        }

        static async Task ThrowAfter(int ms, string message)
        {
            Console.Write("xxx");
          await Task.Delay(ms);
          throw new Exception(message);
        }

输出澳门新萄京官方网站 11

  DontHandle方法调用ThrowAfter后,不会在该处等待,会继续施行,不再保持对ThrowAfter方法的引用。

  DontHandle方法调用ThrowAfter后,不会在该处等待,会继续实施,不再保持对ThrowAfter方法的引用。

  调用Cancel()实际会在从cancellationTokenSource.Token复制的具备取消标识上设置IsCancellationRequested属性。

  注意:重临void的异步方法长久不会等待.异步方法最佳再次来到二个Task类型。

  注意:重临void的异步方法恒久不会等待.异步方法最佳重回一个Task类型。

 到此职责的片段大旨的操作已经完毕了,下一节关切下C#5.0的async/await上下文关键字。

  一.异步方法的要命管理

  一.异步方法的可怜管理

  使用await关键字,将其放在在try/catch中   

  使用await关键字,将其放在在try/catch中   

private static async void HandleOneError()
        {
          try
          {
            await ThrowAfter(2000, "first");
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }
private static async void HandleOneError()
        {
          try
          {
            await ThrowAfter(2000, "first");
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }

 

 

  二.多少个异步方法的百般处理

  2.三个异步方法的那么些管理

  假若根据上边包车型大巴代码,第一个可怜将不会抛出。因为第一个特别已经抛出,直接调到catch块内了。   

  如若依照上边包车型大巴代码,第贰个特别将不会抛出。因为第3个极其已经抛出,直接调到catch块内了。   

private static async void StartTwoTasks()
        {
          try
          {
            await ThrowAfter(2000, "first");
            await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }
private static async void StartTwoTasks()
        {
          try
          {
            await ThrowAfter(2000, "first");
            await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
          }
          catch (Exception ex)
          {
            Console.WriteLine("handled {0}", ex.Message);
          }
        }

  使用Task.WhenAll,不管职责是或不是抛出非凡,都会等到四个义务成功。所以会抛出五个特别。

  使用Task.WhenAll,不管职务是不是抛出万分,都会等到三个职分完毕。所以会抛出多个十一分。

  可是,只雅观见传递给Task.WhenAll方法的第一个任务的丰硕音讯,尽管第三个拾分会抛出,但不会来得:   

  不过,只美观见传递给Task.WhenAll方法的第1个职分的可怜消息,尽管第贰个要命会抛出,但不会呈现:澳门新萄京官方网站:异步编程之基于任务的异步模式,异步编程。   

private async static void StartTwoTasksParallel()
            {
              Task t1 = null;
              Task t2 = null;
              try
              {
                t1 = ThrowAfter(2000, "first");
                 t2 = ThrowAfter(1000, "second");
                await Task.WhenAll(t1, t2);
              }
              catch (Exception ex)
              {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine("handled {0}", ex.Message);
              }
            }
private async static void StartTwoTasksParallel()
            {
              Task t1 = null;
              Task t2 = null;
              try
              {
                t1 = ThrowAfter(2000, "first");
                 t2 = ThrowAfter(1000, "second");
                await Task.WhenAll(t1, t2);
              }
              catch (Exception ex)
              {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine("handled {0}", ex.Message);
              }
            }

  三.使用AggregateException音信重回显示分外

  三.接纳AggregateException消息重返展现十分

  将Task.WhenAll再次来到的结果写到3个Task变量中,catch语句只检索到第四个职务的不行,但足以访问外部任务taskResult的Exception属性。Exception属性是AggregateException类型。那个特别类型定义了InnerExceptions属性,它包罗了守候中的全体特别的列表。   

  将Task.WhenAll重回的结果写到一个Task变量中,catch语句只检索到第二个职务的百般,但能够访问外部任务taskResult的Exception属性。Exception属性是AggregateException类型。那个特别类型定义了InnerExceptions属性,它含有了等候中的全体非常的列表。   

private static async void ShowAggregatedException()
        {
          Task taskResult = null;
          try
          {
            Task t1 = ThrowAfter(2000, "first");
            Task t2 = ThrowAfter(1000, "second");
            await (taskResult = Task.WhenAll(t1, t2));
          }
          catch (Exception ex)
          {
            // just display the exception information of the first task that is awaited within WhenAll
            Console.WriteLine("handled {0}", ex.Message);
            foreach (var ex1 in taskResult.Exception.InnerExceptions)
            {
              Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
            }
          }
        }
private static async void ShowAggregatedException()
        {
          Task taskResult = null;
          try
          {
            Task t1 = ThrowAfter(2000, "first");
            Task t2 = ThrowAfter(1000, "second");
            await (taskResult = Task.WhenAll(t1, t2));
          }
          catch (Exception ex)
          {
            // just display the exception information of the first task that is awaited within WhenAll
            Console.WriteLine("handled {0}", ex.Message);
            foreach (var ex1 in taskResult.Exception.InnerExceptions)
            {
              Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
            }
          }
        }

6.撤销异步方法

6.撤废异步方法

  如若后台任务或者运转非常长日子,就恐怕用的吊销职分。

  若是后台职责可能运转相当长日子,就或者用的撤消任务。

  撤除框架基于支持行为,不是强制性的。3个运营时刻非常长的职分急需检查本身是或不是被打消,在这种景况下,它的劳作正是清理全数已展开的财富,并终止相关职业。

  打消框架基于帮衬行为,不是强制性的。一个运转时刻非常短的职务须要检讨自身是否被注销,在这种状态下,它的做事正是理清全数已张开的财富,并甘休相关工作。

  撤销基于CancellationTokenSource类,该类可用来发送撤销请求。请求发送给引用CancellationToken类的职分,当中CancellationToken类和CancellationTokenSource相关联。   

  裁撤基于CancellationTokenSource类,该类可用于发送撤销请求。请求发送给引用CancellationToken类的天职,当中CancellationToken类和CancellationTokenSource相关联。   

private CancellationTokenSource cts = new CancellationTokenSource();

        //添加一个按钮,用于取消正在运行的任务。使用cts.Cancel();
         private void button5_Click(object sender, EventArgs e)
         {
             if (cts != null)
                 cts.Cancel();
         }

        private async void button4_Click(object sender, EventArgs e)
        {

            string s =  await AsyncTaskTest();
        }

        //向Task类的Run方法传递CancellationToken参数。但需要检查是否请求了取消操作。
         Task<string> AsyncTaskTest()
        {
            return Task.Run(() =>
                {
                cts.Token.ThrowIfCancellationRequested();
                    Thread.Sleep(5000);
                    return "异步完成";
                }
            , cts.Token);
        }
private CancellationTokenSource cts = new CancellationTokenSource();

        //添加一个按钮,用于取消正在运行的任务。使用cts.Cancel();
         private void button5_Click(object sender, EventArgs e)
         {
             if (cts != null)
                 cts.Cancel();
         }

        private async void button4_Click(object sender, EventArgs e)
        {

            string s =  await AsyncTaskTest();
        }

        //向Task类的Run方法传递CancellationToken参数。但需要检查是否请求了取消操作。
         Task<string> AsyncTaskTest()
        {
            return Task.Run(() =>
                {
                cts.Token.ThrowIfCancellationRequested();
                    Thread.Sleep(5000);
                    return "异步完成";
                }
            , cts.Token);
        }

 

 

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站:异步编程之基于任务的异

关键词: