異步調用

異步調用

asynchronous call(異步調用)

一個可以無需等待被調用函式的返回值就讓操作繼續進行的方法

基本介紹

  • 中文名:異步調用
  • 外文名:asynchronous call
  • 領域:函式
  • 傑作:執行緒
  • :。
舉例,實戰用法,異步調用外部數據處理,異步調用原理,異步調用使用方法,測試方法和異步委託,使用 EndInvoke 等待異步調用,使用 WaitHandle 等待異步調用,輪詢異步調用完成,

舉例

異步調用就是你 喊 你朋友吃飯 ,你朋友說知道了 ,待會忙完去找你 ,你就去做別的了。
同步調用就是你 喊 你朋友吃飯 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你們一起去。

實戰用法

作業系統發展到今天已經十分精巧,執行緒就是其中一個傑作。作業系統把 CPU 處理時間劃分成許多短暫時間片,在時間 T1 執行一個執行緒的指令,到時間 T2又執行下一執行緒的指令,各執行緒輪流執行,結果好象是所有執行緒在並肩前進。這樣,編程時可以創建多個執行緒,在同一期間執行,各執行緒可以“並行”完成不同的任務。
單執行緒方式下,計算機是一台嚴格意義上的馮·諾依曼式機器,一段代碼調用另一段代碼時,只能採用同步調用,必須等待這段代碼執行完返回結果後,調用方才能繼續往下執行。有了多執行緒的支持,可以採用異步調用,調用方和被調方可以屬於兩個不同的執行緒,調用方啟動被調方執行緒後,不等對方返回結果就繼續執行後續代碼。被調方執行完畢後,通過某種手段通知調用方:結果已經出來,請酌情處理。
計算機中有些處理比較耗時。調用這種處理代碼時,調用方如果站在那裡苦苦等待,會嚴重影響程式性能。例如,某個程式啟動後如果需要打開檔案讀出其中的數據,再根據這些數據進行一系列初始化處理,程式主視窗將遲遲不能顯示,讓用戶感到這個程式怎么等半天也不出來,太差勁了。藉助異步調用可以把問題輕鬆化解:把整個初始化處理放進一個單獨執行緒,主執行緒啟動此執行緒後接著往下走,讓主視窗瞬間顯示出來。等用戶盯著視窗犯呆時,初始化處理就在背後悄悄完成了。程式開始穩定運行以後,還可以繼續使用這種技巧改善人機互動的瞬時反應。用戶點擊滑鼠時,所激發的操作如果較費時,再點擊滑鼠將不會立即反應,整個程式顯得很沉重。藉助異步調用處理費時的操作,讓主執行緒隨時恭候下一條訊息,用戶點擊滑鼠時感到輕鬆快捷,肯定會對軟體產生好感。

異步調用外部數據處理

異步調用用來處理從外部輸入的數據特別有效。假如計算機需要從一台低速設備索取數據,然後是一段冗長的數據處理過程,採用同步調用顯然很不合算:計算機先向外部設備發出請求,然後等待數據輸入;而外部設備向計算機傳送數據後,也要等待計算機完成數據處理後再發出下一條數據請求。雙方都有一段等待期,拉長了整個處理過程。其實,計算機可以在處理數據之前先發出下一條數據請求,然後立即去處理數據。如果數據處理比數據採集快,要等待的只有計算機,外部設備可以連續不停地採集數據。如果計算機同時連線多台輸入設備,可以輪流向各台設備發出數據請求,並隨時處理每台設備發來的數據,整個系統可以保持連續高速運轉。編程的關鍵是把數據索取代碼和數據處理代碼分別歸屬兩個不同的執行緒。數據處理代碼調用一個數據請求異步函式,然後逕自處理手頭的數據。待下一組數據到來後,數據處理執行緒將收到通知,結束 wait 狀態,發出下一條數據請求,然後繼續處理數據。
異步調用時,調用方不等被調方返回結果就轉身離去,因此必須有一種機制讓被調方有了結果時能通知調用方。在同一進程中有很多手段可以利用,筆者常用的手段是回調、互斥對象和訊息。
回調方式很簡單:調用異步函式時在參數中放入一個函式地址,異步函式保存此地址,待有了結果後回調此函式便可以向調用方發出通知。如果把異步函式包裝進一個對象中,可以用事件取代回調函式地址,通過事件處理例程向調用方發通知。
mutex是 Windows系統提供的一個常用同步對象,以在異步處理中對齊不同執行緒之間的步點。如果調用方暫時無事可做,可以調用 wait 函式等在那裡,此時 mutex處於 nonsignaled 狀態。當被調方出來結果之後,把 mutex對象置於 signaled 狀態,wait函式便自動結束等待,使調用方重新動作起來,從被調方取出處理結果。這種方式比回調方式要複雜一些,速度也相對較慢,但有很大的靈活性,可以搞出很多花樣以適應比較複雜的處理系統。
藉助 Windows訊息發通知是個不錯的選擇,既簡單又安全。程式中定義一個用戶訊息,並由調用方準備好訊息處理例程。被調方出來結果之後立即向調用方傳送此訊息,並通過WParam 和 LParam 這兩個參數傳送結果。訊息總是與視窗 handle關聯,因此調用方必須藉助一個視窗才能接收訊息,這是其不方便之處。另外,通過訊息聯絡會影響速度,需要高速處理時回調方式更有優勢。
如果調用方和被調方分屬兩個不同的進程,由於記憶體空間的隔閡,一般是採用 Windows訊息發通知比較簡單可靠,被調方可以藉助訊息本身向調用方傳送數據。event對象也可以通過名稱在不同進程間共享,但只能發通知,本身無法傳送數據,需要藉助 Windows 訊息和 FileMapping等記憶體共享手段或藉助 MailSlot 和 Pipe 等通信手段。

異步調用原理

異步調用原理並不複雜,但實際使用時容易出莫名其妙的問題,特別是不同執行緒共享代碼或共享數據時容易出問題,編程時需要時時注意是否存在這樣的共享,並通過各種狀態標誌避免衝突。Windows 系統提供的 mutex 對象用在這裡特別方便。mutex同一時刻只能有一個管轄者。一個執行緒放棄管轄權後,另一執行緒才能接管。當某執行緒執行到敏感區之前先接管 mutex,使其他執行緒被 wait函式堵在身後;脫離敏感區之後立即放棄管轄權,使 wait函式結束等待,另一個執行緒便有機會光臨此敏感區。這樣就可以有效避免多個執行緒進入同一敏感區。
由於異步調用容易出問題,要設計一個安全高效的編程方案需要比較多的設計經驗,所以最好不要濫用異步調用。同步調用畢竟讓人更舒服些:不管程式走到哪裡,只要死盯著移動點就能心中有數,不至於象異步調用那樣,總有一種四面受敵、惶惶不安的感覺。必要時甚至可以把異步函式轉換為同步函式。方法很簡單:調用異步函式後馬上調用 wait 函式等在那裡,待異步函式返回結果後再繼續往下走。

異步調用使用方法

測試方法和異步委託

四個示例全部使用同一個長期運行的測試方法 TestMethod。該方法顯示一個表明它已開始處理的控制台信息,休眠幾秒鐘,然後結束。TestMethod 有一個 out 參數(在 Visual Basic 中為 ByRef),它演示了如何將這些參數添加到 BeginInvoke 和 EndInvoke 的簽名中。您可以用類似的方式處理 ref 參數(在 Visual Basic 中為 ByRef)。
下面的代碼示例顯示 TestMethod 以及代表 TestMethod 的委託;若要使用任一示例,請將示例代碼追加到這段代碼中。
注意 為了簡化這些示例,TestMethod 在獨立於 Main() 的類中聲明。或者,TestMethod 可以是包含 Main() 的同一類中的 static 方法(在 Visual Basic 中為 Shared)。

使用 EndInvoke 等待異步調用

異步執行方法的最簡單方式是以 BeginInvoke 開始,對主執行緒執行一些操作,然後調用 EndInvoke。EndInvoke 直到C#異步調用完成後才返回。這種技術非常適合檔案或網路操作,但是由於它阻塞 EndInvoke,所以不要從用戶界面的服務執行緒中使用它。

使用 WaitHandle 等待異步調用

等待 WaitHandle 是一項常用的執行緒同步技術。您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。C#異步調用完成時會發出 WaitHandle 信號,而您可以通過調用它的 WaitOne 等待它。
如果您使用 WaitHandle,則在C#異步調用完成之後,但在通過調用 EndInvoke 檢索結果之前,可以執行其他處理。

輪詢異步調用完成

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 屬性來發現C#異步調用何時完成。從用戶界面的服務執行緒中進行C#異步調用時可以執行此操作。輪詢完成允許用戶界面執行緒繼續處理用戶輸入。

相關詞條

熱門詞條

聯絡我們