日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#中的异步陷阱

發布時間:2025/3/20 C# 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#中的异步陷阱 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文主要介紹異步編程中,常見的異步陷阱:

1、Async沒有異步運行

我們來看下面代碼,猜測他是如何打印出下面的三個字符串:

/*Gotcha #1: Async does not run asynchronously*/ static void Main(string[] args) {Console.WriteLine("begin" + "" + DateTime.Now.ToString() + "");var child = Gotcha1.WorkThenWait();Console.WriteLine("started" + "" + DateTime.Now.ToString() + "");child.Wait();Console.WriteLine("completed" + "" + DateTime.Now.ToString() + "");Console.ReadKey(); } public static async Task WorkThenWait() {Thread.Sleep(5000);Console.WriteLine("work" + "" + DateTime.Now.ToString() + "");await Task.Delay(10000); }

看這段代碼,如果你猜想,他會按順序打印出“begin“,”started”,“work”,“completed”,那樣的話,你就錯了。這段代碼會輸出“begin“,“work”,“started”,“completed”。

可以看出來,本段代碼本來的猜想是,由于WorkThenWait()方法中包含繁重耗時的任務(這里為Thread.Sleep(5000)),所以打算讓他異步執行這個方法,但是,可以看出問題出在await關鍵字用在了該段繁重耗時任務之后,所以后面的child.Wait()方法只是等待了Task.Delay(10000)的執行。

執行結果如下:

?2、忽略結果

我們來看下面代碼,猜測他是如何執行的,是否會等待:

/*Gotcha #2: Ignoring results*/ static void Main(string[] args) {Gotcha2.Handler();Console.ReadKey(); } public static async Task Handler() {Console.WriteLine("Before");Task.Delay(5000);Console.WriteLine("After"); }

看這段代碼,你是否期待它會打印“Before”,等待5秒之后,再打印“After”?當然,又錯了。他會立即打印兩條字符串,直接沒有任何等待。問題出在,雖然Task.Delay返回了Task返回值,但是我們忘記了使用await關鍵字去等待直到他完成。

執行結果如下:

?3、Async void方法

我們來看下面代碼,判斷下是否能成功打印出異常信息:

/*Gotcha #3: Async void methods*/ static void Main(string[] args) {Gotcha3.CallThrowExceptionAsync();Console.ReadKey(); }private static async void ThrowExceptionAsync() {throw new InvalidOperationException(); }public static void CallThrowExceptionAsync() {try{ThrowExceptionAsync();}catch (Exception){Console.WriteLine("Failed");} }

你是否覺得這段代碼會打印“Failed”?當然,這個異常沒有被捕獲到,因為ThrowExceptionAsync方法開始執行并立即返回(這個異常發生在background thread內部)。問題根源在于:對于例如 async void Foo(){...},這種方法,C#編譯器將生成一個返回void的方法,然后它會在后臺創建一個task并執行。這意味著你無法知道這項工作實際何時發生。

?4、Async void lambda函數

如果你將異步lambda函數作為委托傳遞給某個方法時。在這種情況下,C#編譯器將從委托類型推斷方法的類型。如果使用Action delegate,則編譯器生成async void function(這種后臺啟動線程工作并返回void)。如果使用Func<Task> delegate,編譯器講生成返回Task的function。

我們來看下面代碼,判斷這段代碼是在5秒之后執行完(等待所有的Task完成sleeping),或者它立即完成了?

/*Gotcha #4: Async void lambda functions*/ static void Main(string[] args) {Gotcha4.Test();Console.WriteLine("ok"); }public static void Test() {Parallel.For(0, 10, async i => {await Task.Delay(5000);}); }

當然,直接看For無法判斷出他是否等待,我們借助小工具看下如下代碼的源碼:

public void TestMethod() {Parallel.For(0, 10, async i => {await Task.Delay(5000);}); } // AsyncGotchasLib.Class1 public void TestMethod() {int arg_23_0 = 0;int arg_23_1 = 10;Action<int> arg_23_2;if ((arg_23_2 = Class1.<>c.<>9__0_0) == null){arg_23_2 = (Class1.<>c.<>9__0_0 = new Action<int>(Class1.<>c.<>9.<TestMethod>b__0_0));}Parallel.For(arg_23_0, arg_23_1, arg_23_2); }

可以看到For中,lambda函數最終編譯為了Action Delegate,因此這段代碼不會等待5秒,會立即執行完成,它的等待會在后臺線程執行。

?5、嵌套任務

看下面代碼,問題是,下面兩個print直接會不會等待5秒:

/*Gotcha #5: Nesting of tasks*/ static void Main(string[] args) {Gotcha5.Test();Console.ReadKey(); }public async static void Test() {Console.WriteLine("Before");await Task.Factory.StartNew(async () => { await Task.Delay(5000); Console.WriteLine("后臺線程等待5秒后"); });Console.WriteLine("After"); }

同樣,相當意外,并沒有在兩個打印(“Before”,“After”)之間等待。為什么?StratNew 方法接受一個委托,并返回一個Task<T>,其中T表示又delegate返回的類型。在這個方法中,這個delegate返回Task,因此,我們獲得的結果為Task<Task>。使用await關鍵字僅僅等待外部Task的完成(它將立即返回內部task),這代表內部task將被忽略,內部task將在后臺線程執行。

轉載于:https://www.cnblogs.com/SimplePerson/p/7395513.html

總結

以上是生活随笔為你收集整理的C#中的异步陷阱的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。