3

したがって、固定スレッドプールがどのように機能するか(Javaに組み込まれたExecutor.fixedThreadPoolを使用)はある程度理解していると思いますが、私が見ることができることから、通常は実行したいジョブの数が設定されており、開始時にいくつになるかがわかります。プログラム。例えば

int numWorkers = Integer.parseInt(args[0]);
int threadPoolSize = Integer.parseInt(args[1]);
ExecutorService tpes =
    Executors.newFixedThreadPool(threadPoolSize);
WorkerThread[] workers = new WorkerThread[numWorkers];
for (int i = 0; i < numWorkers; i++) {
    workers[i] = new WorkerThread(i);
    tpes.execute(workers[i]);
}

各workerThreadが本当に単純なことを行う場合、その部分は任意です。私が知りたいのは、プールサイズが固定されている(たとえば最大8)が、実行時までタスクを完了するために必要なワーカーの数がわからない場合はどうなるかということです。

具体的な例は次のとおりです。プールサイズが8で、標準入力から読み取っている場合。読みながら、入力を設定されたサイズのブロックに分割しました。これらのブロックのそれぞれは、圧縮できるように(他の情報とともに)スレッドに渡されます。そのため、入力の最後に到達するまで続行する必要があるため、作成する必要のあるスレッドの数がわかりません。また、データが同じ順序に保たれるようにする必要もあります。スレッド2がスレッド1の前に終了し、その作業を送信しただけの場合、私のデータは故障します!

この状況では、スレッドプールは間違ったアプローチでしょうか?それは素晴らしいことのようです(一度に8つ以上のスレッドを使用することはできないので)。

基本的に、私はこのようなことをしたいと思います:

ExecutorService tpes = Executors.newFixedThreadPool(threadPoolSize);
BufferedInputStream inBytes = new BufferedInputStream(System.in);
byte[] buff = new byte[BLOCK_SIZE];
byte[] dict = new byte[DICT_SIZE];
WorkerThread worker;
int bytesRead = 0;

while((bytesRead = inBytes.read(buff)) != -1) {
   System.arraycopy(buff, BLOCK_SIZE-DICT_SIZE, dict, 0, DICT_SIZE);
   worker = new WorkerThread(buff, dict)   
   tpes.execute(worker);
}

これは機能するコードではありませんが、私は自分が欲しいものを説明しようとしているだけです。

少し省略しましたが、buffとdictの値がどのように変化するか、入力の長さがわからないことを確認してください。最初の電話の後ですでによく働く人がいるので、私は実際にこの考えをすることができないと思います!私はworker=new WorkerThreadと言うことはできません。なぜなら、それはすでに既存のスレッド(true、死んでいる可能性のあるスレッド)を指しているのではないからです。明らかに、この実装では、それが機能した場合、私は実行しません。並行して。しかし、私のポイントは、最大プールサイズに達するまでスレッドを作成し続け、スレッドが完了するまで待ってから、入力の最後に達するまでスレッドを作成し続けることです。

また、物事を整理する必要があります。これは本当に厄介な部分です。

4

2 に答える 2

1

@ignisが指摘しているように、並列実行は状況に最適な答えではない場合があります。ただし、より一般的な質問に答えるために、FixedThreadPool以外にも考慮すべきExecutor実装がいくつかあり、そのうちのいくつかは、必要な特性を備えている場合があります。

物事を整理する限り、通常はタスクをエグゼキュータに送信し、送信ごとにFuture(タスクが終了したときに結果を提供することを約束するオブジェクト)を取得します。したがって、タスクを送信した順序でFutureを追跡し、すべてのタスクが完了したら、各Futureでget()を呼び出して、結果を取得できます。

于 2012-10-28T16:29:49.987 に答える
1

WorkerThreadソリューションは完全に問題ありません(唯一のポイントは、のワークロードが非常に小さい場合は並列処理はおそらく必要ないということです)。

スレッドプールの場合、送信されたタスクの数は関係ありません。プール内のスレッドの数が少ない場合も多い場合もありますが、スレッドプールがそれを処理します。

ただし、これは重要です。sの結果のある種の順序に依存しますWorkerThreadが、並列処理を使用する場合、この順序は保証されません。スレッドプールを使用するかどうか、または使用しているワーカースレッドの数などは関係ありません。結果は、任意の順序で終了する可能性が常にあります。

順序を正しく保つにはWorkerThread、コンストラクターで現在のアイテムの番号をそれぞれに指定し、終了後に結果を正しい順序に並べるようにします。

int noOfWorkItem = 0;
while((bytesRead = inBytes.read(buff)) != -1) {
   System.arraycopy(buff, BLOCK_SIZE-DICT_SIZE, dict, 0, DICT_SIZE);
   worker = new WorkerThread(buff, dict, noOfWorkItem++)   
   tpes.execute(worker);
}
于 2012-10-28T16:37:10.910 に答える