當前位置:首頁 » 編程軟體 » net非同步編程

net非同步編程

發布時間: 2024-02-28 04:28:26

㈠ 如何正確理解.NET 4.5和C#5.0中的async/await非同步編程模式

這個await,其實只是把對老版本C#迭代器的慣用法官方化了。現在很多平台都因為一些原因不得不用舊版本的C#,比如unity,想非同步那隻能通過迭代器來做。

async、迭代器都是語法糖,編譯器會幫你實現成一個狀態機匿名類,實例裡面hold住一些臨時變數,記錄一下當前狀態。根據你寫的yield/await,把一個非同步方法拆成幾個同步block,根據一定規則定期的去MoveNext一下,Current是Task那我就根據你配置的線程上下文決定把這個Task跑在哪個線程上。

那麼用await修飾的非同步方法是在哪個線程中被調用的?為什麼上面這個事件處理方法不會阻塞GUI?
我還看到其它一些描述是說使用async/await非同步模式不會生成新的線程,那麼只在原來已有線程的基礎上面如何做到非同步運行?
題主這個例子這個方法就是在UI線程調用的,並且沒有ConfigureAwait(false),所以會在當前await時捕捉的UI線程上下文執行之後的同步block。
至於為什麼不會阻塞,可以簡單理解為執行了第一個block,碰到Delay(4000),給UI線程的定時器掛一個4000時間之後再調用下一個同步塊的回調。

看題主說的書名像是國產的書,這方面還是看《CLR via C#》或者《Concurrency in C# cookbook》比較好。

㈡ 什麼是非同步編程

傳統的同步編程是一種請求響應模型,調用一個方法,等待其響應返回.

非同步編程就是要重新考慮是否需要響應的問題,也就是縮小需要響應的地方。因為越快獲得響應,就是越同步化,順序化,事務化,性能差化。

非同步編程通常是通過fire and forget方式實現,發射事件後即忘記,做別的事情了,無需立即等待剛才發射的響應結果了。(發射事件的地方稱為生產者,而將在另外一個地方響應事件的處理者稱為消費者).非同步編程是一種事件驅動編程,需要完全改變思路,將「請求響應」的思路轉變到「事件驅動」思路上,是一種軟體編程思維的轉變.下面幾種你看參考一下

1、非同步編程模型 (APM) 模式(也稱為 IAsyncResult 模式),其中非同步操作要求 Begin 和 End 方法(例如,非同步寫操作的 BeginWrite 和 EndWrite)。對於新的開發工作不再建議採用此模式。

2、基於事件的非同步模式 (EAP) 需要一個具有 Async 後綴的方法,還需要一個或多個事件、事件處理程序、委託類型和 EventArg 派生的類型。EAP 是在 .NET Framework 2.0 版中引入的。對於新的開發工作不再建議採用此模式。
3、基於任務的非同步模式 (TAP),該模式使用一個方法表示非同步操作的啟動和完成。.NET Framework 4 中引入了 TAP,並且是 .NET Framework 中非同步編程的建議方法。

㈢ C#幾種非同步編程

1、非同步編程模型 (APM) 模式(也稱為 IAsyncResult 模式),其中非同步操作要求 Begin 和 End 方法(例如,非同步寫操作的 BeginWrite 和 EndWrite)。對於新的開發工作不再建議採用此模式。

2、基於事件的非同步模式 (EAP) 需要一個具有 Async 後綴的方法,還需要一個或多個事件、事件處理程序、委託類型和 EventArg 派生的類型。EAP 是在 .NET Framework 2.0 版中引入的。對於新的開發工作不再建議採用此模式。
3、基於任務的非同步模式 (TAP),該模式使用一個方法表示非同步操作的啟動和完成。.NET Framework 4 中引入了 TAP,並且是 .NET Framework 中非同步編程的建議方

㈣ 如何正確理解.NET 4.5和C#5.0中的async/await非同步編程模式

相對於之前Begin/End模式和事件模式,async/await模式讓程序員得以用同步的代碼結構進行非同步編程。async/await入門很方便,但是深入理解卻涉及很多領域,如線程池、同步上下文等等。我斷斷續續接觸了幾個月,稍微有一些心得:


await的作用是等待非同步Task完成,並不是阻塞的。舉個例子,一個非同步方法:

publicasyncTaskCaller()
{
Action0();
awaitMethod();
Action3();
}

publicasyncTaskMethod()
{
Action1();
awaitTask.Delay(1000);
Action2();
}

A.當你在非UI線程A上執行Caller(),將完成以下幾件事:

  1. [線程A]執行Action0()

  2. [線程A]調用await Method()

  3. [線程A]執行Action1()

  4. [線程A]啟動任務Task.Delay(1000),並在線程池裡安插一個新任務,在Task.Delay(1000)完成後,由另一個線程執行6

  5. [線程A]去處理別的事情

  6. [線程B]執行Action2()

  7. [線程B]await Method()返回

  8. [線程B]執行Action3()

其中,線程A和線程B並不保證是同一個線程。如果你在await前後列印線程ID,你會發現ID是不同的。


B.當你在UI線程上執行Caller(),過程有了變化:

  1. [UI線程]執行Action0()

  2. [UI線程]調用await Method()

  3. [UI線程]執行Action1()

  4. [UI線程]啟動任務Task.Delay(1000),並在線程池裡安插一個新任務,在Task.Delay(1000)完成後,由另一個線程執行6

  5. [UI線程]去處理別的事情

  6. [線程C]在UI線程的同步上下文中執行7(類似於在窗體類上執行Invoke()方法)

  7. [UI線程]執行Action2()

  8. [UI線程]await Method()返回

  9. [UI線程]執行Action3()

可見,當使用await方法的線程為UI線程時,程序默認會通過第6步,保證await前後是同一個線程ID。這個當然是有一定性能犧牲的(甚至會造成死鎖,在D里會討論),如果你不想在await完成後回到UI線程,見C。


C. 你可以在UI線程上使用await XXX().ConfigureAwait(false)去替代awaitXXX(),來禁止當await XXX()結束時恢復線程。舉個例子,執行下列代碼是沒問題的(如B里描述的):

privateasyncvoidbutton1_Click(objectsender,EventArgse)
{
this.Text="123";
awaitTask.Delay(1000);
this.Text="321";
}

但是,執行下列代碼就會發生「線程間操作無效」的錯誤:

privateasyncvoidbutton1_Click(objectsender,EventArgse)
{
this.Text="123";
awaitTask.Delay(1000).ConfitureAwait(false);
this.Text="321";//線程間操作無效
}

因為執行

this.Text="321";

的線程已經不再是UI線程。


D. 順便一提,Task.Wait()方法,相比於await Task,會同步地執行Task。但是,如果你在UI線程上Wait的Task里本身又有await,那麼將會產生死鎖:

privatevoidFoo(objectsender,EventArgse)
{
this.Text="123";
Method().Wait();//此處發生死鎖
this.Text="321";//這行永遠也不會執行
}
privateasyncTaskMethod()
{
awaitTask.Delay(1000);
}

為什麼呢?Method().Wait()會阻塞UI線程等待Method()完成,但是參照B過程,在await完成後,Method()完成前,是需要恢復到UI線程的,但是此時UI線程已經被阻塞了,因此死鎖就發生了。

要避免這個死鎖,可以參照C。


E. 說出來你可能不信,上面的都是我手打的。在內容上雖然不一定嚴謹,但希望對樓主和其它新接觸TAP的朋友有一定啟發。

熱點內容
w7恢復出廠設置密碼是多少 發布:2024-11-16 05:23:49 瀏覽:790
方周編譯器 發布:2024-11-16 05:23:12 瀏覽:659
資料庫監控工具 發布:2024-11-16 05:23:07 瀏覽:957
存儲器題型 發布:2024-11-16 05:23:06 瀏覽:85
怎麼設置電腦配置信息 發布:2024-11-16 05:04:26 瀏覽:980
推薦系統php 發布:2024-11-16 05:03:42 瀏覽:11
加密mp3文件 發布:2024-11-16 04:43:04 瀏覽:842
觀瀾ug編程培訓 發布:2024-11-16 04:42:15 瀏覽:639
注冊表中心伺服器地址生成規則 發布:2024-11-16 04:30:19 瀏覽:962
安卓360雙系統怎麼設置 發布:2024-11-16 04:29:32 瀏覽:756