入れ子になったタスクを並列で実行しますが、スレッドセーフティは保証されません。各タスクは独自のThreadで実行され、コンカレンシーの問題が発生する可能性は、ホストシステムのCPU数に応じて増加します。
警告: Apache Antコアはスレッドセーフであると考えられていますが、タスクについてはそのような保証はありません。Antのテストプロセスでは、タスクのスレッドセーフティはテストされません。サードパーティのタスクはスレッドセーフである場合もあれば、そうでない場合もあります。また、<javac>
など、Antのコアタスクの一部は、再入可能ではありません。これは、マルチスレッド環境で使用することを意図せずに設計されたライブラリを使用しているためです。
<parallel>
の主なユースケースは、アプリケーションサーバーやJUnit、TestNGテストスイートなどの外部プログラムを同時に実行することです。javadoc
とjavac
など、大規模なAntタスクシーケンスを並列で実行しようとする場合は、実行するタスクのすべてのコンカレンシーバグを特定して修正する作業を暗黙的に引き受けています。
したがって、このタスクには用途がありますが、マルチコア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>
を使用することで、そのようなサーバーはビルドを停止しません。
これは、サーバーアプリケーションをテストするための典型的なパターンです。1つのスレッドでサーバーが開始され(<wlrun>
タスク)、もう1つのスレッドで3つのタスクが順番に実行されます。<sleep>
タスクは、サーバーが起動する時間を与えるために使用されます。サーバーが使用可能であることを検証できる別のタスクを、<sleep>
タスクの代わりに使用できます。その後、<junit>
テストハーネスが独自のJVMで実行されます。テストが完了すると、サーバーが停止されます(この例では<wlstop>
を使用)。これにより、両方のスレッドが完了します。<parallel>
タスクもこの時点で完了し、ビルドは続行されます。
<parallel> <wlrun ... > <sequential> <sleep seconds="30"/> <junit fork="true" forkmode="once" ... > <wlstop/> </sequential> </parallel>
ここでは、2つの独立したタスクを実行して、ビルド中のリソース使用率を向上させます。この例では、サーブレットが1つのスレッドでコンパイルされ、JSPのセットが別のスレッドでプリコンパイルされます。開発者は、依存関係とAntの外部環境での潜在的な相互作用の両方において、2つのタスクが独立していることを注意する必要があります。ここでは、<javac>
タスクにfork=true
を設定して、新しいプロセスで実行するようにしています。<wljspc>
タスクがVM内でjavacコンパイラを使用する場合(可能性があります)、コンカレンシーの問題が発生する可能性があります。
<parallel> <javac fork="true"...> <!-- compiler servlet code --> <wljspc ...> <!-- precompile JSPs --> </parallel>
この例は、threadCountおよびthreadsPerProcessor属性を使用する典型的なニーズを表しています。これらの40個すべてのタスクを起動すると、システムのメモリとCPU時間が不足する可能性があります。同時実行数を制限することで、CPU、メモリ、ディスクI/Oの競合を減らし、実際により高速に完了することができます。各タスクは独立しており(新しいJVMはすべてフォークされます)、他のタスクに依存しないため、これはthreadCount(およびおそらくthreadsPerProcessor)を使用するのに適しています。
<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>