必威电竞|足球世界杯竞猜平台

異步調用
來源:互聯網

異步調用(asynchronous call),是指一種不需要等待被調用函數返回值就能夠繼續執行的方法。

舉例

異步調用的例子可以理解為你喊你的朋友一起吃飯,即使你的朋友表示稍后會找你,你也可以先去做其他事情。相比之下,同步調用則意味著你需要一直等待直到你的朋友完成工作并與你一同前往。

實戰用法

隨著操作系統的不斷發展,線程已成為其重要組成部分。操作系統能夠將CPU處理時間劃分為多個短暫的時間片,在T1時間執行一個線程的指令,隨后在T2時間執行下一個線程的指令,使得各個線程似乎是在并行地執行。在這種情況下,程序員可以創建多個線程并在同一時間段內執行,每個線程都可以“并行”地完成不同的任務。

在單線程模式下,計算機遵循嚴格的約翰·馮·諾依曼架構,當一段代碼調用另一段代碼時,必須采用同步調用,即必須等待這段代碼執行完畢并返回結果后,調用方才能夠繼續執行后續代碼。然而,得益于多線程支持,我們可以采用異步調用,調用方和被調用方可以屬于不同的線程。調用方啟動被調用方線程后,不必等待對方返回結果即可繼續執行后續代碼。被調用方執行完畢后,可以通過某種方式通知調用方:結果已經得出,請適當處理。

在計算機中,某些處理可能較為耗時。當調用此類處理代碼時,如果調用方一直處于等待狀態,將會顯著影響程序性能。例如,某個程序啟動后需要打開文件讀取其中的數據,然后再根據這些數據進行一系列初始化處理,那么程序的主窗口可能會延遲顯示,導致用戶體驗不佳。通過異步調用,我們能夠將整個初始化處理放在一個單獨的線程中,主線程啟動此線程后繼續向下執行,從而使主窗口快速顯示。當用戶專注于窗口時,初始化處理已經在后臺悄然完成。程序穩定運行后,我們還可以繼續使用異步調用來提高人機交互的即時響應性。當用戶點擊鼠標觸發操作時,如果該操作相對耗時,再次點擊鼠標時可能不會立即響應,這會使整個程序顯得緩慢。通過異步調用來處理耗時的操作,可以讓主線程隨時準備處理下一條消息,從而實現快速響應用戶的點擊,提升用戶對軟件的好感度。

異步調用外部數據處理

異步調用對于處理來自外部的輸入數據非常有效。假設計算機需要從一臺低速設備獲取數據,然后進行一段較長的數據處理過程,采用同步調用顯然是不合理的:計算機首先向外部設備發出請求,然后等待數據輸入;而外部設備向計算機發送數據后,也需要等待計算機完成數據處理后再發出下一條數據請求。在這段時間里,雙方都有等待期,延長了整個處理過程。實際上,計算機可以在處理數據之前先發出下一條數據請求,然后立即處理接收到的數據。如果數據處理的速度較快,那么只需要等待的是計算機,外部設備可以連續不斷地采集數據。如果計算機同時連接有多臺輸入設備,它可以依次向各臺設備發出數據請求,并隨時處理每臺設備發送的數據,整個系統可以保持連續高效運轉。關鍵在于將數據采集工具代碼和數據處理代碼分別分配給兩個不同的線程。數據處理代碼調用一個數據請求異步函數,然后直接處理當前的數據。當下一組數據到達后,數據處理線程將收到通知,結束等待狀態,發出下一條數據請求,然后繼續處理數據。

在異步調用過程中,調用方不必等待被調用方返回結果,因此必須有一種機制能夠讓被調用方在得到結果后通知調用方。在同一進程中,有許多可用的機制,包括回調、互斥對象和消息。

回調是一種簡單的機制:在調用異步函數時,在參數中提供一個函數地址,異步函數將其保存下來,當有結果時回調此函數,以便向調用方發出通知。如果將異步函數封裝在一個對象中,可以使用事件代替回調函數地址,通過事件處理例程向調用方發送通知。

Mutex是Windows系統提供的常用同步對象,可用于在異步處理中協調不同線程之間的步驟。如果調用方暫時沒有其他任務,可以調用wait函數在此處等待,此時Mutex處于非信號狀態。當被調用方獲得結果后,將Mutex對象設置為信號狀態,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在獨立于Main()的類中聲明。或者,TestMethod可以是包含Main()的同一類中的靜態方法(在Visual Basic中為Shared)。

使用EndInvoke等待異步調用

異步執行方法的最簡單方式是使用BeginInvoke開始,對主線程執行一些操作,然后調用EndInvoke。EndInvoke直到異步調用完成后才會返回。這種技術適用于文件或網絡操作,但由于它阻塞了EndInvoke,因此請勿從用戶界面的服務線程中使用它。

使用WaitHandle等待異步調用

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

輪詢異步調用完成

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

參考資料 >

異步調用.博客.2024-10-27

JavaScript 異步編程.菜鳥教程.2024-10-27

異步調用.知乎.2024-10-27

生活家百科家居網