簡單地使用線程之一:使用異步編程模型

.NetFramework的異步編程模型從本質上來說是使用線程池來完成異步的任務,異步委托、HttpWebRequest等都使用了異步模型。

這里我們使用異步委托來說明異步編程模型。

首先,我們來明確一下,對于多線程來說,我們需要關注哪些問題。

“線程是一段執行中的代碼流”,從這句話中,我們可以關注這段代碼流何時開始執行、何時結束、從主線程如何傳遞參數至從子線程、從子線程如何返回結果至主線程?

問題1:在異步編程模型中,子線程何時開始執行?

對于異步編程模型來說,使用BeginXXX來開始執行線程。

我們首先來看一個實例(來自《C#高級編程(第7版)》)。

pulic delegate int TestMethodDelegate(int data,int ms);

static int TestMethod(int data,int ms)

{

? ? Console.WriteLine("TestMethod started.");

? ? Thread.Sleep(ms);

? ? Console.WriteLine("TestMethod completed.");

? ? return data++;

}

?

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,null,null);

? ? //其中,1,3000分別對應委托的兩個參數,后面兩個null位置的參數是兩個固定的參數,是留給異步回調的時候用的(稍后會講到)。

}

問題2:在異步編程模型中,子線程何時結束?

其實,這個問題對于只有一個主線程的單線程程序來說不會成為問題,因為一段代碼執行過程中,執行到這個方法的最后一行,這個方法也就執行結束了。

但在多線程中,由于主線程與子線程有一個從屬關系,加上線程還有前臺線程與后臺線程之分,使得子線程的結束時機需要加以判斷,判斷規則如下。

(1).如果子線程是后臺線程,那么主線程結束時,不管子線程是否執行完畢,子線程將結束。

(2).如果子線程是前強線程,那么主線程結束時,子線程將繼續執行,直至結束。

PS:由于線程池里面的線程均為后臺線程,因此,異步編程模型中,只會存在第1種情況。

那么問題來了:如果子線程為后臺線程,且子線程的處理時間非常地長,那主線程如果處理到最后一條代碼時,那子線程就會關閉,那子線程的處理邏輯就沒走完,就會出錯。

我們該如何防止這樣的問題發生呢?

直觀地來說,在主線程中等待子線程完成是一種可行的方案,而要實現這種方案,我們至少需要知道子線程是否已經執行完成?

在異步編程模型中,我們可以使用輪詢(Polling)、等待句柄(WaitHandler)、EndInvoke()方法來達到這樣的效果。

方法1:輪詢(Polling)

我們改寫Main()方法如下:

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,null,null);

? ? while(!ar.IsCompleted)

? ? {

? ? ? ? ?//do something?

? ?}

? ?//執行到這里的時候,子線程已經執行完畢了。

}

方法2:等待句柄(WaitHandler)

我們再次改寫Main()方法。

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,null,null);

? ? while(true)

? ? {

? ? ? ? ?if(ar.AsyncWaitHandler.WaitOne(50,false))//每等待50毫秒,然后判斷是否子線程是否已完成,如果已完成,則break。

? ? ? ? {

? ? ? ? ? ????//執行到這里的時候,子線程已經執行完畢了。

? ? ? ? ? ? break;

? ? ? ? }

? ? }

? ?//主線程....

}

方法3:EndInvoke()方法

再次改用Main()方法:

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,null,null);

? ? ar.EndInvoke();//會一直等待,直到委托方法執行完成,其實,也可以通過它將子線程的結果返回至主線程中,可以參考后面的問題4.

? ?//主線程....

}

問題3:在異步編程模型中,從主線程如何傳遞參數至從子線程?

這個問題我們其實已經在問題1中有所展示,我們在BeginInvoke的方法中向委托中傳遞了兩個參數。

?

問題4:在異步編程模型中,從子線程如何返回結果至主線程?

在問題2中,我們使用EndInvoke()等待委托方法執行完成,其實我們也可采用這個方法得到子線程的返回值。

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,null,null);

? ? int result=ar.EndInvoke();//得到返回值,返回值類型這里為int,即委托定義的返回值類型。? ??

? ?//主線程....

}

?

問題5:異步回調

異步回調很有用,它的出現應該說是極大地擴展了異步模型下的多線程威力。為什么這么說?

考慮一種情況,如果主線程需要120秒完成執行,子線程需要80秒,在主線程第90秒的時候開始有啟動子線程,主線程等待子線程結束,最后結束主線程。那么,整個主線程就至少需要90+80秒的時間來完成執行,中間很明顯有不少主線程等待子線程的時間。有沒有更好的辦法?

如果主線程不需要子線程的返回結果,而子線程結束后還會有一些單獨的處理邏輯(比如清理對象、單獨的處理數據等),我們可以采用異步回調來解決這個問題。

異步回調:簡而言之,就是異步任務完成之后,再回過頭來調用的方法。

先看一個異步回調的例子:

static Main()

{

? ??TestMethodDelegate dl=TestMethod;

? ? IAsyncResult ar=dl.BeginInvoke(1,3000,TestMethodCompleted,dl);

? ?//主線程....

}

static?TestMethodCompleted(IAsyncResult ar)

{

? ???//do something

? ??TestMethodDelegate dl=(TestMethodDelegate?)ar.AysncState;

? ? dl.EndInvoke();//可以傳遞委托實例進來,在這里獲得委托線程的結果。? ??

}

?

在這里,我們關注BeginInvoke方法的第3個和第4個參數。

第3個參數,TestMethodCompleted即是回調方法,它是一個AsyncCallback類型的委托。

第4個參數是傳遞給回調方法的參數,在回調方法中可以用ar.AsyncState來獲得這個參數。

使用回調方法,必須注意這個方法要從委托線程中調用,而不是從主線程中調用,如果從主線程中調用,那就變成了普通的方法調用。

另外,如果使用Lambda表達式可以實現一些更簡潔優雅的偌。?

static Main()?

{?

? ??TestMethodDelegate dl=TestMethod;?

? ? dl.BeginInvoke(1,3000,

? ? ? ? ar=>{

? ? ? ? ? ? ? ? ? ? ?int result=dl.EndInvoke(ar);

? ? ? ? ? ? ? ? ? ? ?//do something

? ? ? ? ? ? ? ? },

? ? ? ? null) ;

? ?//主線程....?

}?

//這里,不需要把一個值賦予BeginInvoke()方法的最后一個參數,因為Lambda表達式可以直接訪問該作用域外部的變量dl。但是,Lambsa表達式的實現代碼仍是從委托線程中調用,只是不是很明顯。

?

轉載于:https://www.cnblogs.com/gudi/p/4499155.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257311.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257311.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257311.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ShowType=0,交換機命令showinterfacestype0/port_#switchport|trunk用于顯 - 信管網

交換機命令show interfaces type0/port_# switchport|trunk用于顯示中繼連接的配置情況,下面是顯示例子:2950#show interface fastEthernet0/1 switchportName: fa0/1Switchport: EnabledAdministrative mode: trunkOperational Mode: trunkAdministrati…

SQL SERVER學習筆記(二)數據庫管理

第二部分:數據庫管理 單詞記憶:transact:處理 create:創建 execute:執行、完成 一、 SQL Server的特性 1、 安裝簡便:為了便于安裝、使用和管理,SQL Server2000提供了一組管理和開發工具。 …

SQL——快速定位相關的外鍵表

轉載于:https://www.cnblogs.com/mingle/p/4506422.html

Linux安裝glibc(升級版本)

2019獨角獸企業重金招聘Python工程師標準>>> glibc下載地址:http://ftp.gnu.org/gnu/glibc/ 這里下載 glibc-2.15: http://ftp.gnu.org/gnu/glibc/glibc-2.15.tar.gz glibc-ports-2.15: http://ftp.gnu.org/gnu/glibc/glibc-ports…

定義列表的特點html,HTML的列表表格表單知識點

無序列表格式 有序列表格式第一項 …

Javascript 獲取url參數,hash值 ,cookie

/*** 獲取請求參數* param key* returns {*}*/ function getRequestParameter(key){var params getRequestParameters();return params[key]; }/*** 獲取請求參數列表* returns {{}}*/ function getRequestParameters(){var arr (location.search || "").replace(/…

C# 中使用 ThoughtWorks.QRCode.dll 生成指定尺寸和邊框寬度的二維碼

本文介紹在 C# 中使用 ThoughtWorks.QRCode.dll 生成指定尺寸和邊框寬度的二維碼。網上文章大多只是簡單介紹內置參數的設置,根據我的使用目的,增加了自定義目標二維碼圖片尺寸和白邊邊框。有需要的朋友們可以試一下,如有bug歡迎指正。 首先&…

html設置百度協議,網站HTML結構SEO要求說明(含移動站)

網頁結構一、網頁中主體結構標簽一一對應。網頁頭部區域網頁底部區域網頁邊框區域網頁導航區域網頁章節、頁眉、頁腳詳情頁文章區域詳情頁作者信息詳情頁中文章的發布日期列表頁中文章列表區域二、其他說明1、首頁head中標注Meta標簽協議,標識對應的網頁瀏覽&#x…

【Fanvas技術解密】HTML5 canvas實現臟區重繪

先說明一下,fanvas是筆者在企鵝公司開發的,即將開源的flash轉canvas工具。 臟區重繪(dirty rectangle)并不是一門新鮮的技術了,這在最早2D游戲誕生的時候就已經存在。 復雜的術語或概念就不多說,簡單說,臟區重繪就是每…

javascript 學習教程

1&#xff0c;JavaScript 是一種輕量級的編程語言&#xff0c;是可插入 HTML 頁面的編程代碼。 2,以<script>標簽開始&#xff0c;以</script>標簽結束。 3,引用放在外部文件的擴展名為.js的腳本文件 <script src"myScript.js"></script> 4&…

我國非按勞分配收入

我國現階段非按勞分配收入探討 我國社會主義初級階段的個人消費品分配&#xff0c;是通過多種分配方式實現的。除了占主體地位的按勞分配方式之外&#xff0c;還存在許多種類的非按勞分配方式。因此&#xff0c;在我國城鄉居民個人收入總額中&#xff0c;除了一部分按勞分配收入…

html調用js里面的函數,html如何調用js函數

html調用js函數的方法&#xff1a;1、用控件本身進行調用&#xff1b;2、通過javascript中的時間控件定時執行&#xff1b;3、通過getElementById調用&#xff1b;4、通過document.getElementsByName調用。本文操作環境&#xff1a;Windows7系統、html5&&javascript1.8…

大部分人都會做錯的經典JS閉包面試題

2019獨角獸企業重金招聘Python工程師標準>>> 由工作中演變而來的面試題 JS中有幾種函數 創建函數的幾種方式 三個fun函數的關系是什么&#xff1f; 函數作用域鏈的問題 到底在調用哪個函數&#xff1f; 后話 轉載于:https://my.oschina.net/u/3687565/blog/1549046

STM32片上Flash內存映射、頁面大小、寄存器映射

轉自&#xff1a;http://blog.chinaunix.net/uid-20617446-id-3847242.html 一、怎么看Flash大小 1.1 通過型號 型號會印在MCU表面&#xff0c;可以通過觀察獲得&#xff0c;我的是STM32F103RBT6(以下分析基于這個型號)&#xff0c;對照下圖的STM32產品命名&#xff0c;可知STM…

如何設計實現一個地址反解析服務?

http://www.cnblogs.com/LBSer/p/4507829.html 一、什么是地址反解析 我們都知道手機定位服務&#xff0c;其本質是匯總各種信號得出一個經緯度坐標&#xff08;x,y&#xff09;&#xff08;具體定位原理可以參考&#xff1a;LBS定位技術、基于樸素貝葉斯的定位算法&#xff09…

html5 hr代碼縮減比例,HTML HR size用法及代碼示例

DOM HR size屬性用于設置或返回元素的size屬性的vlue。用法:它返回HR大小屬性。hrobject.size用于設置HR大小屬性。hrobject.size"value"屬性值&#xff1a;value:它包含指定HR元素高度的像素值。返回值&#xff1a;它返回一個字符串值&#xff0c;該值代表HR元素的高…

【轉】C++標準轉換運算符static_cast

static_cast<new_type> (expression) 雖然const_cast是用來去除變量的const限定&#xff0c;但是static_cast卻不是用來去除變量的static引用。其實這是很容易理解的&#xff0c;static決定的是一個變量的作用域和生命周期&#xff0c;比如&#xff1a;在一個文件中將變量…

MySQL Binlog Mixed模式記錄成Row格式

背景&#xff1a; 一個簡單的主從結構&#xff0c;主的binlog format是Mixed模式&#xff0c;在執行一條簡單的導入語句時&#xff0c;通過mysqlbinlog導出發現記錄的Binlog全部變成了Row的格式&#xff08;明明設置的是Mixed&#xff09;&#xff0c;現在就說說在什么情況下Bi…

update語句中使用子查詢

55. 更改 108 員工的信息: 使其工資變為所在部門中的最高工資, job 變為公司中平均工資最低的 job 1). 搭建骨架 update employees set salary (), job_id () where employee_id 108; 2). 所在部門中的最高工資 select max(salary) from employees where department_id ( s…

html后臺數據分類管理,細分數據.html

&#xfeff;細分數據$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resources/reload.html; };…