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

C#異步編程幾點需要注意的地方

 更新時間:2020年05月28日 12:00:02   作者:依樂祝  
這篇文章我們來討論下關(guān)于C#異步編程幾個不成文的建議,希望對你寫出高性能的異步編程代碼有所幫助

盡量不要編寫返回值類型為void的異步方法

在通常情況下,建議大家不要編寫那種返回值類型為void的異步方法,因為這樣做會破壞該方法的啟動者與方法本身之間的約定,這套約定本來可以確保主調(diào)方能夠捕獲到異步方法所發(fā)生的異常。

正常的異步方法是通過它返回的Task對象來匯報異常的。如果執(zhí)行過程中發(fā)生了異常,那么Task對象就進入了faulted(故障)狀態(tài)。主調(diào)方在對異步方法所返回的Task對象做await操作時,該對象若已處在faulted狀態(tài),系統(tǒng)則會將執(zhí)行異步方法的過程中所發(fā)生的異常拋出,反之,若Task尚未執(zhí)行到拋出異常的那個地方,則主調(diào)方的執(zhí)行進度會暫停在await語句這里,等系統(tǒng)稍后安排某個線程繼續(xù)執(zhí)行該語句下方的那些代碼時,異常才會拋出。

總結(jié)一句話就是:void的異步方法發(fā)生異常時,開發(fā)者得不到任何通知,程序既不會觸發(fā)普通的異常處理程序,也不會把這些異常記錄下來??傊@會讓相關(guān)的線程默默的終止掉。

不要把同步方法與異步方法組合起來使用

用async關(guān)鍵字來修飾的方法意味著該方法有可能會在執(zhí)行完所有工作之前就把控制權(quán)返回給主調(diào)方,而且,它返回給主調(diào)方的是個代表工作進度的Task對象。主調(diào)方可以查詢此對象的狀態(tài),以了解該工作是否已經(jīng)完成、尚未完成還是在執(zhí)行過程中發(fā)生了故障。此外,這種方法還在暗示主調(diào)方:本方法所執(zhí)行的工作可能要花費很長時間,因此建議你先去做其他一些事情,稍后再來向我索要結(jié)果。

與此相反,如果把某個方法設(shè)計成同步方法,那么意味著當(dāng)該方法執(zhí)行完畢時,它的后置條件必定能夠得到滿足。無論這個方法要花多長時間去完成工作,它都會采用與主調(diào)方相同的資源來完成,主調(diào)方必須等這個方法徹底執(zhí)行完畢才能向下執(zhí)行。

這兩種方法單獨寫起來都很清晰,但是如果把他們組合在一起就會讓方法變得十分難用,而且有可能導(dǎo)致各種bug,如死鎖。因此,這里提出兩條重要的原則。第一,不要讓同步方法必須等待異步方法執(zhí)行完畢才能往下執(zhí)行(盡量不用Wait()以及.result這些阻塞式的方法)。第二,不要讓異步方法把雖然耗時很長、計算量很大但是完全可以由自己執(zhí)行的工作轉(zhuǎn)交給另一個異步任務(wù)去做。'

當(dāng)然對于第二點,這并不是說計算量較大的任務(wù)絕對不能放在單獨的線程中執(zhí)行,而是說不應(yīng)該把只用一個線程就能迅速做好的任務(wù)刻意的拆解成許多個較小的部分,并把他們分別放在多個新的線程上執(zhí)行,而是應(yīng)該把整個任務(wù)都交給某個線程來執(zhí)行才對。

使用異步方法時應(yīng)盡量避免線程分配

異步任務(wù)看上去好像很神奇,因為這種任務(wù)刻意轉(zhuǎn)移到另一個地方去做,使得開啟這項任務(wù)的異步方法可以在該任務(wù)完成之后,從早前暫停的地方繼續(xù)往下推進。不過,要想發(fā)揮異步任務(wù)的功效,就必須保證把這項任務(wù)交出去確實能夠少占用一些資源,而不是僅僅會在相似的資源之間進行上下文切換。

如:對于一個控制臺程序,如果只是執(zhí)行一項計算量較大且耗時較長的任務(wù)(或者說,運行時間較長的CPU密集型的任務(wù)),那么把該任務(wù)單獨放在另一個線程中并沒有多大好處。因為這樣做只能讓工作線程始終處于繁忙狀態(tài),而主線程則必須一直卡在那里等待工作線程把任務(wù)做完。在這種情況下,實際上是用兩個線程來完成原本只需要一個線程就能做好的工作,造成了資源的浪費。

避免不必要的上下文切換

目前C#代碼中使用async以及await實現(xiàn)的異步方法默認是把await之后的代碼放在早前捕獲的那個上下文中執(zhí)行的,這是因為這樣做比較穩(wěn)妥,它最多只會引發(fā)幾次無謂的上下文切換,而不會使程序出現(xiàn)重大的錯誤,與之相反,如果系統(tǒng)不把山下文切換回去,那么萬一遇到的是只能在特定的上下文中才能執(zhí)行的代碼,那么程序就有可能崩潰。因此,無論有沒有必要切換上下文,系統(tǒng)都會切換至早前捕獲到的那個上下文,并把await之后的語句放在那個上下文執(zhí)行。

如果不想讓系統(tǒng)做出這樣的安排,那么可以調(diào)用ConfigureAwait()方法。這表示接下來的那些代碼無須放在早前捕獲的上下文中執(zhí)行。例如在很多程序集中,await語句之后的那些代碼一般都與上下文無關(guān),因此與,可以調(diào)用Task對象的ConfigureAwait()方法告訴系統(tǒng),在執(zhí)行完這項任務(wù)之后,不必專門把await下面的代碼放在早前捕獲的上下文中運行。如下所示:

public static async Task<XElement> ReadPacket(string url)
{
	var result=await DownloadAsync(url)
				.ConfigureAwait(false);
	return XElement.Parse(result);			
}

C#語言默認讓程序把await下面的語句都放在早前捕獲的上下文中執(zhí)行,這樣做雖然較為安全,但是會降低程序的效率。因此為了讓用戶能夠更加順暢的使用程序,我們應(yīng)該調(diào)整代碼的結(jié)構(gòu),把必須運行在特定上下文的代碼剝離出來,并盡量考慮在await語句那里調(diào)用ConfigureAwait(false),使得程序可以把語句下面的代碼放在默認上下文中運行,而不是切換回早前的上下文。

通過Task對象來進行異步開發(fā)

Task(任務(wù))是一種抽象機制,可以用來表示某項工作,于是,就能夠把該工作轉(zhuǎn)交給其他資源去完成。Task類型以及與之相關(guān)的類與結(jié)構(gòu)體提供了豐富的API,讓開發(fā)者可以操控Task對象以及由該對象所表示的工作。此外,Task對象自身也具備一些方法與屬性,可以用來操作本對象所表示的任務(wù)。這些Task對象可以合起來構(gòu)成一項比較大的任務(wù),他們之間既能夠按照順序執(zhí)行,也能夠平行的執(zhí)行。

可以通過await語句來確保某些任務(wù)之間能夠按照一定的順序執(zhí)行,也就是說,只有當(dāng)該語句所要等待的那項工作完畢之后,語句下方的代碼才能夠執(zhí)行。

總之,由于C#提供了一套豐富的API,因此可以寫出相當(dāng)優(yōu)雅的算法來處理Task對象,并對這些對象所表示的任務(wù)進行安排。對任務(wù)的用法理解的越透徹,寫出來的異步代碼越清晰。

這里簡單說明兩個常用的API:

WhenAll:會根據(jù)現(xiàn)有的一批任務(wù)創(chuàng)建出一項新的任務(wù),只有當(dāng)那批任務(wù)全部執(zhí)行完畢時,這項新人物才能夠完成。對Task.WhenAll所返回的新任務(wù)進行await操作會獲得一份列表,早前的那些任務(wù)的執(zhí)行結(jié)果就位于該列表中。

WhenAny:為了盡早的獲得某個結(jié)果,可能啟動多項任務(wù),使得他們分別從不同的途徑去獲取該結(jié)果。只要其中有一項任務(wù)完成,你的目標(biāo)就達成了,針對這項需求,可以考慮使用Task.WhenAny方法,并把自己所創(chuàng)建的那批任務(wù)傳進去。對WhenAny方法所返回的Task對象進行await操作可以獲取到一項任務(wù),它指的就是這批任務(wù)中最先執(zhí)行完畢的那項任務(wù)。

考慮實現(xiàn)任務(wù)的取消協(xié)議

異步任務(wù)的編程模型(也叫基于任務(wù)的異步編程模型)提供了標(biāo)準的API,用來取消任務(wù)或者廣播任務(wù)的執(zhí)行進度。雖然這些API是可選的,但如果某項任務(wù)確實能夠匯報其進度,或者能夠予以取消,那就可以考慮用合適的辦法來實現(xiàn)這些API。

針對需要取消的任務(wù),我們可以通過CanclelationTokenSource對象來進行取消操作。這種對象是一種起到中介作用的對象。該對象處在有可能發(fā)出取消請求的客戶代碼與支持取消功能的那項操作之間。

如果正在執(zhí)行的任務(wù)發(fā)現(xiàn)客戶端想要取消該操作,那么它就會通過ThrowIfCanclellationRequested()方法拋出TaskCanclledException異常,庸醫(yī)表示整個工作流程沒有能夠完全得到執(zhí)行。

此外,返回值類型為void類型的異步方法不應(yīng)該支持取消功能。

緩存泛型異步方法的返回值

可能你在進行異步編程的時候?qū)Ξ惒椒椒ㄔO(shè)置的返回類型都是Task或者Task<T>,然而有些時候把返回值類型設(shè)為Task可能會影響性能。如果某個循環(huán)或某段代碼需要頻繁的運行,那么系統(tǒng)就有可能分配很多個Task對象,從而占用相當(dāng)多的資源。好在C#提供了一種新的類型,叫做ValueTask<T>對象,他用起來比普通的Task更為高效。該類型是值類型,因此創(chuàng)建這種類型的對象時,不需要再分配額外的空間。這個好處使得我們可以多創(chuàng)建一些這樣的對象,而不用擔(dān)心它會像Task對象那樣占據(jù)過多的資源。如果你的異步方法可以根據(jù)早前緩存起來的結(jié)果直接返回相應(yīng)的值,那么尤其應(yīng)該考慮把返回值類型設(shè)置為ValueTask<T>。

其次,ValueTask提供了一個能夠接受Task參數(shù)的構(gòu)造函數(shù),這個構(gòu)造函數(shù)會在其內(nèi)部等候該Task的執(zhí)行結(jié)果。

總結(jié)

今天分享的內(nèi)容比較多,而且很多都比較難理解,不過確實是寫出高性能異步方法所必須要掌握的技巧。由于時間較短,因此也沒來得及通過代碼進行講述,所以需要有一定的基礎(chǔ)才能看懂,不過還是希望對您有所幫助。

以上就是C#異步編程幾點需要注意的地方的詳細內(nèi)容,更多關(guān)于C#異步編程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入C#任務(wù)管理器中應(yīng)用程序選項隱藏程序本身的方法詳解

    深入C#任務(wù)管理器中應(yīng)用程序選項隱藏程序本身的方法詳解

    本篇文章是對在C#任務(wù)管理器中應(yīng)用程序選項隱藏程序本身的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C#交錯數(shù)組淺析

    C#交錯數(shù)組淺析

    這里介紹C#交錯數(shù)組,數(shù)組是具有同一類型的一組值,數(shù)組是引用類型的,因此存在內(nèi)存堆中。數(shù)組中的元素值可以在定義數(shù)組時賦予,也可以在定義數(shù)組后對單個元素進行賦值
    2012-09-09
  • C#實現(xiàn)網(wǎng)頁畫圖功能

    C#實現(xiàn)網(wǎng)頁畫圖功能

    這篇文章主要為大家詳細介紹了C#實現(xiàn)網(wǎng)頁畫圖功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C#編寫Windows服務(wù)程序詳細步驟詳解(圖文)

    C#編寫Windows服務(wù)程序詳細步驟詳解(圖文)

    本文介紹了如何用C#創(chuàng)建、安裝、啟動、監(jiān)控、卸載簡單的Windows Service 的內(nèi)容步驟和注意事項,需要的朋友可以參考下
    2017-09-09
  • c#事件使用示例詳解

    c#事件使用示例詳解

    這篇文章主要介紹了c#事件使用方法,下面我們利用一個例子來加深我們對事件的理解,需要的朋友可以參考下
    2014-04-04
  • C#Url操作類封裝、仿Node.Js中的Url模塊實例

    C#Url操作類封裝、仿Node.Js中的Url模塊實例

    這篇文章主要介紹了C#Url操作類封裝、仿Node.Js中的Url模塊,實例分析了C#Url操作類封裝的技巧,非常具有實用價值,需要的朋友可以參考下。
    2016-10-10
  • 深入c# GDI+簡單繪圖的具體操作步驟(三)

    深入c# GDI+簡單繪圖的具體操作步驟(三)

    前兩篇已經(jīng)基本向大家介紹了繪圖的基本知識.那么,我就用我們上兩篇所學(xué)的,做幾個例子.我們先來做一個簡單的--仿QQ截圖
    2013-05-05
  • C#中設(shè)置textbox限制條件的方法

    C#中設(shè)置textbox限制條件的方法

    這篇文章主要介紹了C#中設(shè)置textbox限制條件的方法,可實現(xiàn)設(shè)置像數(shù)量、價格、金額等的textbox的限制條件,用戶只能輸入數(shù)字或小數(shù),是非常實用的技巧,需要的朋友可以參考下
    2014-12-12
  • C# Linq讀取XML文件的實例

    C# Linq讀取XML文件的實例

    C# Linq讀取XML文件的實例,需要的朋友可以參考一下
    2013-05-05
  • C#獲取DICOM圖像像素的像素值的代碼詳解

    C#獲取DICOM圖像像素的像素值的代碼詳解

    DICOM即醫(yī)學(xué)數(shù)字成像和通信,是醫(yī)學(xué)圖像和相關(guān)信息的國際標(biāo)準(ISO 12052),它定義了質(zhì)量能滿足臨床需要的可用于數(shù)據(jù)交換的醫(yī)學(xué)圖像格式,這篇文章主要介紹了C#獲取DICOM圖像像素的像素值的方法,需要的朋友可以參考下
    2024-07-07

最新評論