c 基於委託的非同步程式設計模型(APM)測試用例

2022-02-25 23:43:08 字數 4390 閱讀 7226

很多時候,我們需要程式在執行某個操作完成時,我們能夠知道,以便進行下一步操作。

但是在使用原生執行緒或者執行緒池進行非同步程式設計,沒有乙個內建的機制讓你知道操作什麼時候完成,為了克服這些限制,基於委託的非同步程式設計模型應運而生。

通過定義**函式能夠實現非同步程式設計,委託是乙個工具,類似語c++的函式指標,當我們在使用委託時。可以傳入乙個符合其定義的方法。從編譯器的層面看,定義乙個委託,相當於定義了乙個類,該類擁有乙個委託鏈,還有三個方法,invoke用於同步呼叫,而begininvoke和endinvoke則是用於非同步呼叫。

先來對這三個方法進行說明:

invoke方法的輸入輸出和委託本身相同。注意:invoke方法的主要功能就是幫助你在ui執行緒上呼叫委託所指定的方法。invoke方法首先檢查發出呼叫的執行緒(即當前執行緒)是不是ui執行緒,如果是,直接執行委託指向的方法,如果不是,它將切換到ui執行緒,然後執行委託指向的方法。不管當前執行緒是不是ui執行緒,invoke都阻塞直到委託指向的方法執行完畢,然後切換回發出呼叫的執行緒(如果需要的話),返回。

begininvoke的輸出是iasyncresult,輸入除了委託本身的輸入,還包括乙個**函式asynccallback,以及包括了乙個object的型別引數,允許我們向非同步委託傳遞任何型別的資訊。如果把乙個**函式傳入begininvoke,它會在委託執行完成後自動執行。

endinvoke方法的輸入總是iasyncresult,輸出則是和委託本身的輸出相同。如果呼叫endinvoke時,iasyncresult物件表示的非同步操作還未完成,則endinvoke將在非同步操作未完成之前阻塞呼叫執行緒(非常重要)。

如何理解這些方法的輸入輸出?我們可以把begininvoke 作為呼叫的開始,當呼叫完時,我們希望有乙個**函式,可以在希望的時候呼叫,從而讓非同步方法主動通知我們自己以及完成。so begininvoke的輸入除了委託本身的輸入外,還需要乙個回到函式asynccallback(當然也可以不寫這個函式,傳入null,這將失去主動通知的好處)。另外乙個object型別的state引數,允許我們向非同步委託傳輸任意型別的資訊。這個引數,我們能在**函式中獲取到,這更加方便實現各種業務邏輯。

示例1:獲取非同步委託的執行結果

class

program

if (number == 1

)

for (int i = 2; i <= number; i++)

else

}return

b; }

static

void main(string

args)

}

執行結果:(在執行時,endinvoke一直在等待計算結果,阻塞了主線程12秒,實際上和同步呼叫無異,因此,我們應該使用**函式)

begininvoke和endinvoke是由乙個iasyncresult介面物件聯絡在一起

system.iasyncresult介面包括:

1、乙個object型別的asyncstate,儲存主線程傳來的的資訊。

2、乙個布林型別,iscompleted,當其為真,非同步委託執行完畢。

3、乙個型別為waithandle的屬性asyncwaithandle.waithandle有個方法waitone,可以指定最長等待時間。

示例:

static

void main(string

args)

console.writeline(

"結束執行:

" +datetime.now.tostring());

console.readkey();

}

示例2:通過**函式的方式獲得非同步委託的執行結果**函式的作用是當委託完成後,可以主動通過主線程自己已經完成。我們可以在begininvoke中定義**函式,這將在委託完成後自動執行,也就是說,執行緒將執行完**函式才回到執行緒池,而不是直接回到池子中。

回到函式的型別是asynccallback,其也是乙個委託,傳入引數必須是iasyncresult,而且沒有返回值,那麼我們怎麼獲取返回值呢?

此時,我們可以通過**函式的傳入引數iasyncresult來做。我們把引數顯示轉換為asyncresult的形式。asyncresult實現了iasyncresult,它的屬性asyncdelegate是object型別的,可以指向其他地方物件的引用。此時我們可以在**函式中建立乙個委託,令其型別和main中建立的委託相同,然後,將其賦值給asyncdelegatee(需要轉換)。這時,該委託就和main中的那個毫無二致。現在我們可以呼叫endinvoke獲取結果了。而且這次呼叫不會阻塞,**如下

static

void main(string

args)

public

delegate

bool isprimeslowdelegate(int

number);

public

static

bool isprimeslow(int

number)

if (number == 1

)

for (int i = 2; i <= number;i++)

else

}return

b; }

//////

**函式

/// ///

public

static

void

callback(iasyncresult iar)

catch

(exception exp)

}

主線程立即執行完成,**函式在計算完成後自動呼叫。

**函式的引數物件:

這就是真正的非同步了,主線程拍完任務後還可以做其他事,而子執行緒在任務完成後執行**函式。

主線程還可以向子執行緒傳輸任何型別的自定義資料,這通過begininvoke的最後乙個引數實現。由於它是object型別,所以任何型別都可以傳輸。在子執行緒中,我們通過呼叫iasyncresult的asyncstate屬性獲取主線程傳來的資料。該示例中,紅圈即為傳遞的引數

示例3:使用執行緒統一取消模型進行取消

使用委託的非同步程式設計模型也可以使用執行緒統一取消模型進行取消。首先,我們需要為為委託和委託目標方法加入cancellationtoken輸入引數(必須修改委託定義才行,因為begininvoke不支援傳入cancellationtoken)。

然後在委託目標方法中,呼叫throwifcancellationrequested(在迴圈中,保持一直監聽),最後,需要在回到函式中加入try-catch,因為begininvoke不拋operationcanceledexception異常,只有endinvoke才會。為了不阻塞主線程,**函式獲取結果的endinvoke是唯一 的選擇。**如下

static

void main(string

args)

public

delegate

bool isprimeslowdelegate(int

number,cancellationtoken token);

public

static

bool isprimeslow(int

number,cancellationtoken token)

if (number == 1

)

for (int i = 2; i <= number;i++)

else

}return

b; }

//////

**函式

/// ///

public

static

void

callback(iasyncresult iar)

catch

(operationcanceledexception cancelexp)

catch

(exception exp)

}

取消執行**函式中,endinvoke丟擲異常:

注意:使用者在任務完成之前取消了,會丟擲異常,任務完成後取消,並不會丟擲異常

即使提前取消了任務,也會呼叫**函式,丟擲異常。

無論任務成功完成還是被取消,iasyncresult物件的is'com'p'leted屬性都是true;

如果委託傳入小於0,和1的資料,也會丟擲異常,為了捕獲此類以及其他非取消執行緒異常。(使用catch(exception exp)進行捕獲)

非同步程式設計模型 APM

原文 apm是.net中非同步程式設計模型的縮寫 asynchronous programing model 通過非同步程式設計,使得我們的程式可以更加高效的利用系統資源.1.apm例子 net中的非同步模型非常完善,只要看到begin 者end 方法。基本都是相對 方法的非同步呼叫方式。注 是方法...

基於事件的非同步程式設計

基於事件的非同步模式具有多執行緒應用程式的優點,同時隱藏了多執行緒設計中固有的許多複雜問題。使用支援此模式的類,你將能夠 同時執行多個操作,每個操作完成時都會接到通知。等待資源變得可用,但不會停止 阻止 你的應用程式。使用熟悉的事件和委託模型與掛起的非同步操作通訊。支援基於事件的非同步模式的類將具有...

C 深度學習 Task(基於任務的非同步模型)

一 task關鍵字解釋 task 類的表示的單個操作不會返回乙個值,通常以非同步方式執行。task 物件是一種的中心思想 基於任務的非同步程式設計模式 首次引入.net framework 4 中。因為由執行工作 task 物件通常上非同步執行乙個執行緒池執行緒而不是以同步方式在主應用程式執行緒中,...