平行執行巢狀任務,不保證執行緒安全性。每個任務將在自己的執行緒中執行,同時執行問題發生的機率會隨著主機系統的 CPU 數量而增加。
警告:雖然 Apache Ant 核心被認為是執行緒安全的,但任務並未在 Ant 的測試過程中針對執行緒安全性進行測試,因此無法提供此類保證。第三方任務可能執行緒安全,也可能不安全,而 Ant 的某些核心任務(例如 <javac>
)絕對不是可重入的。這是因為它們使用從未設計為在多執行緒環境中使用的函式庫。
<parallel>
的主要使用案例是同時執行外部程式(例如應用程式伺服器)和 JUnit 或 TestNG 測試組。任何嘗試同時執行大型 Ant 任務序列(例如 javadoc
和 javac
)的人,都必須明確承擔找出並修正他們執行的任務中所有並行錯誤的任務。
因此,雖然此任務有其用途,但應視為進階任務,應在某些批次處理或測試情況下使用,而不是在多核心 CPU 上加快建置時間的簡易技巧。
屬性 | 說明 | 必要 |
---|---|---|
threadCount | 要使用的執行緒最大數量。 | 否 |
threadsPerProcessor | 每個可用處理器要使用的執行緒最大數量 (Java 1.4 以上) | 否;遞延至 threadCount |
timeout | 執行終止前的毫秒數 | 否 |
failonany | 如果任何巢狀任務失敗,任務執行將在該點完成,而不會等到任何其他任務完成。 | 否;預設為 false。 |
pollInterval | 目前沒有任何效果 | 否;預設為 1000 |
平行任務在 Ant 建置檔案中有多種用途,包括
任何有效的 Ant 任務都可以嵌入在 parallel
任務中,包括其他 parallel
任務,儘管無法保證任務在這種環境中會執行緒安全。
在 parallel
任務中的任務執行期間,主執行緒將會被封鎖,等待所有子執行緒完成。如果執行在逾時或嵌套任務失敗時終止,且 failonany 旗標已設定,則 parallel
任務將會完成,而不會等待其他執行緒中的其他嵌套任務完成。
如果 <parallel>
任務中的任何任務失敗,且 failonany 未設定,則其他執行緒中的剩餘任務將會繼續執行,直到所有執行緒都已完成。在這種情況下,parallel
任務也會失敗。
parallel
任務可以與 sequential 任務結合,以定義要在平行區塊中的每個執行緒上執行的任務順序。
threadCount
屬性可用於設定執行可用的最大執行緒數。當不存在時,所有子任務將會一次執行。當存在時,同時執行的最大任務數不會超過指定的執行緒數。此外,每個任務將會按其給定的順序啟動。但是,不保證執行速度或任務完成順序,只保證每個任務會在下一任務之前啟動。
如果您使用的是 Java 1.4 或更新版本,您也可以使用 threadsPerProcessor,可用的執行緒數將會是處理器數的開始倍數(然而,沒有與特定處理器的關聯性)。這將會覆寫 threadCount 中的值。如果在任何舊版 JVM 上指定 threadsPerProcessor,則 threadCount 中的值將會按原樣使用。
在使用 threadCount 和 threadsPerProcessor 時,應小心確保建置不會陷入僵局。這可能是因為 waitfor
等任務在會解除 waitfor
的任務發生之前就佔用了所有可用的執行緒。這並非 Java 語言層級執行緒語意的替代方案,最適合用於「極度平行」的任務。
parallel
任務支援一個 <daemons>
巢狀元素。這是一個清單,其中包含要平行執行在守護執行緒中的任務。parallel
任務不會等待這些任務完成。但是,由於是守護執行緒,它們不會阻止 Ant 完成,並終止執行緒。在 parallel
任務本身完成之前,守護執行緒中發生的失敗會被報告,並可能導致 parallel
擲出例外。parallel
完成後發生的失敗不會被報告。
例如,守護任務可以用於啟動測試伺服器,而這些伺服器可能無法從 Ant 輕鬆終止。透過使用 <daemons>
,此類伺服器不會停止建置。
這是測試伺服器應用程式的典型模式。在一個執行緒中,伺服器會啟動 (<wlrun>
任務)。另一個執行緒包含三個按順序執行的任務。<sleep>
任務用於讓伺服器有時間啟動。可以將有能力驗證伺服器是否可用的另一個任務用於取代 <sleep>
任務。<junit>
測試架構隨後會在它自己的 JVM 中執行。一旦測試完成,伺服器就會停止 (在此範例中使用 <wlstop>
),允許兩個執行緒完成。<parallel>
任務也會在此時完成,然後建置會繼續進行。
<parallel> <wlrun ... > <sequential> <sleep seconds="30"/> <junit fork="true" forkmode="once" ... > <wlstop/> </sequential> </parallel>
在此,兩個獨立任務執行以在建置期間達成更好的資源利用。在此範例中,一些 servlet 在一個執行緒中編譯,而一組 JSP 在另一個執行緒中預編譯。開發人員需要小心,這兩個任務在它們的相依性方面和在 Ant 外部環境中它們的潛在互動方面都是獨立的。在此,我們設定 <javac>
任務的 fork=true
,以便它在一個新程序中執行;如果 <wljspc>
任務在 VM 中使用 javac 編譯器 (它可能使用),可能會出現並行問題。
<parallel> <javac fork="true"...> <!-- compiler servlet code --> <wljspc ...> <!-- precompile JSPs --> </parallel>
此範例代表使用 threadCount 和 threadsPerProcessor 屬性的典型需求。同時執行所有 40 個工作可能會讓系統的記憶體和 CPU 時間癱瘓。透過限制同時執行的數量,您可以減少 CPU、記憶體和磁碟 I/O 的競爭,因此實際上可以更快完成。這也是使用 threadCount(以及可能使用 threadsPerProcessor)的良好候選,因為每個工作都是獨立的(每個新的 JVM 都會分岔)且不依賴於其他工作。
<macrodef name="dbpurge"> <attribute file="file"/> <sequential> <java jar="utils/dbpurge.jar" fork="true" > <arg file="@{file}/> </java> </sequential> </macrodef> <parallel threadCount="4"> <dbpurge file="db/one"/> <dbpurge file="db/two"/> <dbpurge file="db/three"/> <dbpurge file="db/four"/> <dbpurge file="db/five"/> <dbpurge file="db/six"/> <dbpurge file="db/seven"/> <dbpurge file="db/eight"/> <!-- repeated about 40 times --> </parallel>