天天看點

具有依賴關系的并行操作執行

一、問題分析

我們知道,較之串行化的操作,并行計算将多個任務同時執行,進而充分利用了資源,提高了應用的整體性能。對于多個互不相幹的操作,我們可以直接按照異步的方式執行就可以。但是,我們遇到的很多情況下是,部分操作之間具有互相依賴的關系,一個操作需要在其他依賴的操作執行完成後方可執行。 以下圖為例,每一個圓圈代表要執行的操作,操作之間的肩頭代表它們之間的依賴關系。

<a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/799856d3fd88_14A22/clip_image002_2.jpg"></a>

我們需要一個元件,幫助我們完成這樣的工作:将相應的操作和依賴關系直接添加到一個容器中,我們的元件能夠自動分析操作之間的依賴關系,在執行的時候根據依賴編排執行順序。

二、采用并行操作執行器

使用我所提供的這樣一個并行操作執行器(ParallelExecutor),可以幫我們解決這個問題。首先對操作本身進行抽象,用以下三個屬性來描述一個并行計算場景中的操作:

 Operation ID: 操作的唯一辨別,字元類型

 Action:操作具體執行的功能,使用Action代理表示

 Depedencies:依賴操作清單

在使用ParallelExecutor對操作進行并行執行之前,我們需要通過ParallelExecutor的兩個AddOperation方法添加需要執行的操作。AddOperation定義如下。其中dependencies代表以來操作ID數組,傳回值為目前建立的操作ID。

對于上圖中的操作的依賴結構,我們通過下面的代碼将所有的操作添加到建立的ParallelExecutor之中并執行。在這裡的具體實作的操作僅僅是列印出操作的ID,以便我們清楚地知道操作執行的先後順序是否滿足依賴關系:

由于是操作的并行執行,線程排程的不确定性使每次輸出的結果各有不同。但是無論如何,需要滿足上圖中展現的依賴關系。下面是其中一種執行結果,可以看出這是合理的執行順序。

三、操作是如何被執行的

實作這樣的并行計算有很多種解決方案。不同的解決方案大都展現在對于單一的操作該如何執行上。在我們提供這個解決方案中,我按照這樣的方案來執行任意一個操作:

直接執行無依賴的操作

如果需要執行的操作并不依賴于任何一個操作(比如C2),那麼我們直接運作就好了,這沒有什麼好說的。

先執行依賴操作,通過注冊事件的方式執行被依賴的操作

如果一個操作依賴于一組操作,在執行之前注冊依賴操作的結束事件實作,被依賴操作的執行發生在某個一個依賴操作的Completed事件觸發後。具體來講,上圖中C1具有兩個以來操作B1和B2,在初始化時,C1上會有一個用于計算尚未執行的依賴操作的個數,并注冊B1和B2得操作結束事件上面。當B1和B2執行結束後,會觸發該事件。每次事件觸發,C1上的計數器将會減1,如果計數器為0,則表明所有的依賴操作執行結束,則執行C1相應的操作。

四、具體實作

現在我們來看看詳細設計和具體實作。首先通過下面的類圖看看涉及到的所有類型。其中Operation類型是最為重要的一個類型,它代表一個具體的操作。

<a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/799856d3fd88_14A22/clip_image004_2.jpg"></a>

操作的屬性

一個操作具有如下屬性:

ID:String類型,操作的唯一辨別

Action:Action類型,操作具體是實作的功能

Dependencies:Operation數組,依賴的操作

Status:Operation枚舉,操作目前的狀态

ExecutionContext:ExecutionContext類型,用于傳遞線程執行的上下文

操作事件

目前操作執行的狀态通過OperationStatus表示,四個枚舉值分别表示被建立、正在運作、運作結束和失敗(抛出異常)。

操作還具有三個時間,分别在開始執行、結束執行和執行失敗時觸發。這三個事件名稱分别為OperationStarted、OperationCompleted和OperationFailed。

OperationStarted和OperationCompleted事件對應的參數類型為OperationEventArgs。OperationEventArgs直接繼承自EventArgs,并定義了一個Operation屬性代表對應的Operation對象。

OperationFailed的事件參數類型為OperationFailedEventArgs。繼承自OperationEventArgs,在此基礎上添加了一個Exception類型的Error屬性,表示抛出的異常。

操作初始化和事件注冊

在第三節中已經談到過了,被依賴操作的執行通過的依賴操作執行完成後觸發OperationCompleted事件的是實作。事件注冊必須在ParallelExecutor執行之前完成,在這裡我定義了一個Initialize方法,在裡面完成事件注冊工作:

操作執行

ParallelExecutor通過調用Operation的Execute方法執行相應的操作。在Execute方法中,如果是獨立的操作,則執行執行,否則異步執行依賴操作,這是一個遞歸的過程。操作的具體實作定義在DoExecute方法中。

ParallelExecutor

ParallelExecutor提供操作的添加和整體執行。添加操作實作在兩個重載的AddOperation方法中,邏輯并不複雜。當執行Execute方法對所有的操作進行并行執行的時候,需要調用Initialize方法對每個操作進行初始化。然後異步調用每個操作的Execute方法即可。

作者:蔣金楠

微信公衆賬号:大内老A

如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識别二維碼)關注個人公衆号(原來公衆帳号蔣金楠的自媒體将會停用)。

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

<a href="http://www.cnblogs.com/artech/archive/2009/05/22/1487386.html">原文連結</a>

繼續閱讀