亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#實(shí)現(xiàn)基于任務(wù)的異步編程模式

 更新時(shí)間:2022年04月11日 15:08:23   作者:Ruby_Lu  
本文詳細(xì)講解了C#實(shí)現(xiàn)基于任務(wù)的異步編程模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一.延續(xù)任務(wù)

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方法返回一個(gè)Task<string>對(duì)象。該Task<string>對(duì)象包含任務(wù)創(chuàng)建的信息,并保存到任務(wù)完成。Task類(lèi)的ContinueWith方法定義了任務(wù)完成后就調(diào)用的代碼。
        private static void CallerWithContinuationTask()
        {

          var t1 = GreetingAsync("Stephanie");


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


        }

由于不使用await,線程不會(huì)在方法中等待,會(huì)執(zhí)行完CallerWithContinuationTask()的代碼。不會(huì)再ContinueWith這里等待,所以需要一個(gè)前臺(tái)線程,不然會(huì)關(guān)閉所以線程。

二.同步上下文

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關(guān)鍵字,當(dāng)await完成后,不需要進(jìn)行任何處理,就能訪問(wèn)UI線程。默認(rèn)情況下,生成的代碼就會(huì)把線程轉(zhuǎn)換到擁有同步上下文的線程中。調(diào)用異步方法的線程分配給了同步上下文,await完成之后將繼續(xù)執(zhí)行。
如果不使用相同的同步上下文,必須調(diào)用Task類(lèi)的ConfigureAwait(false).例如,一個(gè)WPF應(yīng)用程序,其await后面的代碼沒(méi)有任何用到UI元素的代碼。在這種情況下,避免切換到同步上下文會(huì)執(zhí)行的更快。

string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);

三.使用多個(gè)異步方法

在一個(gè)異步方法里,可以調(diào)用一個(gè)或多個(gè)異步方法。如何編寫(xiě)代碼,取決于一個(gè)異步方法的結(jié)果是否取決于另一個(gè)異步方法。

1.按順序調(diào)用異步方法

下面的例子,第第二個(gè)異步方法依賴于第一個(gè)異步方法的結(jié)果,await關(guān)鍵字就很有用。

  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.使用組合器

如果第二個(gè)異步方法獨(dú)立于第一個(gè),每個(gè)異步方法可以都不使用await,而是把每個(gè)異步方法的返回結(jié)果賦值給Task變量,就會(huì)運(yùn)行的更快。

  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組合器可以接受多個(gè)同一類(lèi)型的參數(shù),并返回同一類(lèi)型的值。
  • Task.WhenAll是在所有傳入方法的任務(wù)都完成了才返回Task。
  • WhenAny是在其中一個(gè)傳入方法的任務(wù)完成了就返回。

Task.WhenAll定義了幾個(gè)重載版本。如果所有的任務(wù)返回相同的類(lèi)型,那么該類(lèi)型的數(shù)組可用于await返回的結(jié)果。

string[] result = await Task.WhenAll(t1, t2);

四.轉(zhuǎn)換異步模式

http://chabaoo.cn/article/244023.htm講了三種異步編程的模式。
并非所有的.NET Framework類(lèi)在.NET 4.5中都引入了新的異步方法。還有許多類(lèi)只提供類(lèi)BeginXXX和EndXXX方法的異步模式,可以使用TaskFactory類(lèi)的FromAsync方法,它可以把使用異步模式的方法轉(zhuǎn)換為基于任務(wù)的異步模式的方法。

/創(chuàng)建一個(gè)委托,并引用同步方法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方法的前兩個(gè)參數(shù)是委托類(lèi)型,傳入BeginGreeting, EndGreeting的地址。后兩個(gè)參數(shù)是輸入的參數(shù)和對(duì)象狀態(tài)參數(shù)。
        private static async void ConvertingAsyncPattern()
        {
          string r = await Task<string>.Factory.FromAsync<string>(BeginGreeting, EndGreeting, "Angela", null);
          Console.WriteLine(r);
        }

五.錯(cuò)誤處理

如果調(diào)用異步方法沒(méi)有等待,將異步方法放在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方法調(diào)用ThrowAfter后,不會(huì)在該處等待,會(huì)繼續(xù)執(zhí)行,不再保持對(duì)ThrowAfter方法的引用。
注意:返回void的異步方法永遠(yuǎn)不會(huì)等待.異步方法最好返回一個(gè)Task類(lèi)型。

1.異步方法的異常處理

使用await關(guān)鍵字,將其放在在try/catch中

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

2.多個(gè)異步方法的異常處理

如果按照下面的代碼,第二個(gè)異常將不會(huì)拋出。因?yàn)榈谝粋€(gè)異常已經(jīng)拋出,直接調(diào)到catch塊內(nèi)了。

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,不管任務(wù)是否拋出異常,都會(huì)等到兩個(gè)任務(wù)完成。所以會(huì)拋出兩個(gè)異常。
但是,只能看見(jiàn)傳遞給Task.WhenAll方法的第一個(gè)任務(wù)的異常信息,雖然第二個(gè)異常會(huì)拋出,但不會(huì)顯示:

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返回的結(jié)果寫(xiě)到一個(gè)Task變量中,catch語(yǔ)句只檢索到第一個(gè)任務(wù)的異常,但可以訪問(wèn)外部任務(wù)taskResult的Exception屬性。Exception屬性是AggregateException類(lèi)型。這個(gè)異常類(lèi)型定義了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);
            }
          }
        }

六.取消異步方法

如果后臺(tái)任務(wù)可能運(yùn)行很長(zhǎng)時(shí)間,就可能用的取消任務(wù)。
取消框架基于協(xié)助行為,不是強(qiáng)制性的。一個(gè)運(yùn)行時(shí)間很長(zhǎng)的任務(wù)需要檢查自己是否被取消,在這種情況下,它的工作就是清理所有已打開(kāi)的資源,并結(jié)束相關(guān)工作。
取消基于CancellationTokenSource類(lèi),該類(lèi)可用于發(fā)送取消請(qǐng)求。請(qǐng)求發(fā)送給引用CancellationToken類(lèi)的任務(wù),其中CancellationToken類(lèi)和CancellationTokenSource相關(guān)聯(lián)。

private CancellationTokenSource cts = new CancellationTokenSource();
        
        //添加一個(gè)按鈕,用于取消正在運(yùn)行的任務(wù)。使用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類(lèi)的Run方法傳遞CancellationToken參數(shù)。但需要檢查是否請(qǐng)求了取消操作。
         Task<string> AsyncTaskTest()
        {
            return Task.Run(() =>
                {
                cts.Token.ThrowIfCancellationRequested();
                    Thread.Sleep(5000);
                    return "異步完成";
                }
            , cts.Token);
        }

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論