8

負荷分散されたスレッドプールを探していますが、これまでのところ成功していません。(負荷分散が正しい表現であるかどうかわからない)。私が達成しようとしていることを説明しましょう。

パート1:私には8から10の単一のタスクを持つジョブがあります。6コアCPUで、このタスクを8スレッドで並行して実行します。これにより、最高のパフォーマンスが得られるようです。1つのタスクの準備ができたら、別のタスクを開始できます。10個のタスクがすべて完了すると、完全なジョブが完了します。通常、ジョブは30〜60秒で完了します。

パート2:残念ながら、作業に2時間以上かかる場合があります。計算する必要のあるデータ量があるため、これは正しいです。悪い点は、job1がすべてのスレッドを使用しているため、job1の実行中は他のジョブを開始できないことです(すべてのスレッドの継続時間が同じであると想定)。

私の最初のアイデア:12のスレッドを持ち、最大3つのジョブを並行して許可します。しかし:つまり、仕事が1つしかない場合、couは完全に実現されません。

他に仕事がないときに、仕事1のCPUパワーをフルに活用できるソリューションを探しています。しかし、他のジョブの実行中に他のジョブを開始する必要がある場合は、両方のジョブにCPUパワーを割り当てたいと思います。そして、3番目または4番目のジョブが表示されたら、CPUパワーを4つのジョブすべてに公平に割り当てたいと思います。

私はあなたの答えに感謝します...

前もって感謝します

4

3 に答える 3

6

1つの可能性はThreadPoolExecutor、異なる種類のタスクキューで標準を使用することです。

public class TaskRunner {
  private static class PriorityRunnable implements Runnable,
            Comparable<PriorityRunnable> {
    private Runnable theRunnable;
    private int priority = 0;
    public PriorityRunnable(Runnable r, int priority) {
      this.theRunnable = r;
      this.priority = priority;
    }

    public int getPriority() {
      return priority;
    }

    public void run() {
      theRunnable.run();
    }

    public int compareTo(PriorityRunnable that) {
      return this.priority - that.priority;
    }
  }

  private BlockingQueue<Runnable> taskQueue = new PriorityBlockingQueue<Runnable>();

  private ThreadPoolExecutor exec = new ThreadPoolExecutor(8, 8, 0L,
            TimeUnit.MILLISECONDS, taskQueue);

  public void runTasks(Runnable... tasks) {
    int priority = 0;
    Runnable nextTask = taskQueue.peek();
    if(nextTask instanceof PriorityRunnable) {
      priority = ((PriorityRunnable)nextTask).getPriority() + 1;
    }
    for(Runnable t : tasks) {
      exec.execute(new PriorityRunnable(t, priority));
      priority += 100;
    }
  }
}

ここでの考え方は、新しい仕事があるときに電話をかけるということです

taskRunner.runTasks(jobTask1, jobTask2, jobTask3);

そして、キュー内の既存のタスク(存在する場合)とうまくインターリーブするようにタスクをキューに入れます。1つのジョブがキューに入れられ、そのタスクの優先順位番号がj 1 t 1 = 3、j 1 t 2 = 103、およびj 1 t 3 =203であるとします。他のジョブがない場合、これらのタスクは可能な限り迅速に次々に実行されます。ただし、独自の3つのタスクを持つ別のジョブを送信すると、これらには優先順位番号j 2 t 1 = 4、j 2 t 2 = 104、およびj 2 t 3 = 204が割り当てられます。つまり、キューは次のようになります。

j 1 t 1、j 2 t 1、j 1 t 2、j 2t2など

ただし、これは完全ではありません。すべてのスレッドが現在(ジョブ1のタスクで)動作している場合、ジョブ1のタスクの1つが完了するまで、ジョブ2の最初のタスクを開始できません(外部で検出する方法がない限り)。これと、ジョブ1のタスクの一部を中断して再キューイングします)。物事をより公平にする最も簡単な方法は、実行時間の長いタスクを小さなセグメントに分割し、それらを個別のタスクとしてキューに入れることです。個々のジョブには、プール内のスレッドよりも多くのタスクが含まれるようにする必要があります。一部のタスクは、スレッドに直接割り当てられるのではなく、常にキューで開始されるようにします(アイドル状態のスレッドがある場合はexec.execute()、キューをまったく通過せずに、タスクをスレッドに直接渡します)。

于 2013-01-19T15:06:02.647 に答える
1

お使いのマシンは6コアCPUなのでと思います。ジョブスレッドごとに6つのワーカースレッドを用意することをお勧めします。そのため、1つのスレッドが新しいジョブを取得すると、最大6つの並列ワーカーが単一のジョブで作業を開始します。これにより、一度に1つのジョブしかない場合に、CPUの全電力を確実に消費できます。

また、Java7のフォークと結合の概念も参照してください。References_1References_2References_3
References_4 newcachedthreadpool()についても学習します




Java newCachedThreadPool()とnewFixedThreadPool

于 2013-01-19T14:43:48.700 に答える
1

カナガが示唆しているように、最も簡単な方法はCPUをオーバーサブスクライブすることですが、それぞれ8スレッドを開始します。競合他社からのオーバーヘッドがいくらかあるかもしれませんが、単一の仕事の状況に到達した場合、それはCPUを完全に利用します。OSは、各スレッドに時間を与えることを処理します。

あなたの「最初のアイデア」もうまくいくでしょう。アイドル状態のスレッドは、実際にタスクを実行していない場合、8つの動作中のスレッドからリソースを取得しません。ただし、複数のジョブが実行されている場合は、CPUリソースが均等に分散されません。

これらのさまざまなパイプラインをテストして、パイプラインのパフォーマンスを確認できるセットアップはありますか?

于 2013-01-19T15:20:05.033 に答える