web-dev-qa-db-ja.com

Java:CPUコアに従ってスレッドをスケーリングする方法は?

私は上手ではありませんJavaプログラマー、それはただの趣味ですが、私は平均的なもの以上のものを知りたいと思っています。

Javaの複数のスレッドに関する数学的問題を解決したい。私の数学の問題は、複数のスレッドで解決したい作業単位に分けることができます。

ただし、一定量のスレッドを処理するのではなく、CPUコアの量に対応するスレッドの量を使用します。私の問題は、このための簡単なチュートリアルがインターネットで見つからなかったことです。私が見つけたのは、固定スレッドの例です。

それで、あなたは良いtuturialへのリンクで私を助けることができますか、または私に簡単で良い例を与えることができますか?それは本当に素晴らしいだろう:)

100
Andreas Hornig

静的ランタイムメソッド availableProcessors を使用して、Java仮想マシンで使用可能なプロセスの数を決定できます。使用可能なプロセッサーの数を決定したら、それを作成しますスレッドの数とそれに応じて作業を分割します。

Update:さらに明確にするため、スレッドはJavaの単なるオブジェクトであるため、他のオブジェクトを作成するのと同じように作成できます。したがって、上記のメソッドを呼び出して、2つのプロセッサを返すことがわかったとしましょう。驚くばかり。これで、新しいスレッドを生成し、そのスレッドの作業を分割し、スレッドを起動するループを作成できます。ここに私が意味することを示すためのいくつかの擬似コードがあります:

int processors = Runtime.getRuntime().availableProcessors();
for(int i=0; i < processors; i++) {
  Thread yourThread = new AThreadYouCreated();
  // You may need to pass in parameters depending on what work you are doing and how you setup your thread.
  yourThread.start();
}

独自のスレッドの作成の詳細については、 このチュートリアルに進んでください 。また、スレッドの作成については Thread Pooling をご覧ください。

113
JasCav

このようなものについては、おそらくJava.util.concurrentフレームワークもご覧ください。何かのようなもの:

ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// Do work using something like either
e.execute(new Runnable() {
        public void run() {
            // do one task
        }
    });

または

    Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return null;
        }
    });
    future.get();  // Will block till result available

これは、独自のスレッドプールなどに対処するよりもはるかに優れています。

62
DaveC

オプション1:

newWorkStealingPool from Executors

_public static ExecutorService newWorkStealingPool()
_

使用可能なすべてのプロセッサーをそのターゲット並列処理レベルとして使用して、ワークスチールスレッドプールを作成します。

このAPIを使用すると、ExecutorServiceにコアの数を渡す必要はありません。

grepcode からのこのAPIの実装

_/**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
_

オプション2:

newFixedThreadPoolExecutorsからのAPIまたはExecutorServiceを返す_other newXXX constructors_

_public static ExecutorService newFixedThreadPool(int nThreads)
_

nThreadsをRuntime.getRuntime().availableProcessors()に置き換えます

オプション3:

ThreadPoolExecutor

_public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue)
_

Runtime.getRuntime().availableProcessors()をパラメーターとしてmaximumPoolSizeに渡します。

7
Ravindra babu

Doug Lea(コンカレントパッケージの著者)には、関連する可能性のあるこのペーパーがあります。 http://gee.cs.oswego.edu/dl/papers/fj.pdf

Fork JoinフレームワークがJava SE 7に追加されました。以下に参照をいくつか示します。

http://www.ibm.com/developerworks/Java/library/j-jtp11137/index.html Brian Goetzによる記事

http://www.Oracle.com/technetwork/articles/Java/fork-join-422606.html

7
David Soroko

標準的な方法は、Runtime.getRuntime()。availableProcessors()メソッドです。ほとんどの標準CPUでは、ここで最適なスレッド数(実際のCPUコア数ではありません)が返されます。したがって、これはあなたが探しているものです。

例:

ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

このようなexecutorサービスのシャットダウンを忘れないでください(そうしないとプログラムは終了しません)。

service.shutdown();

ここでは、将来ベースのMTコード(説明のため、オフトピック)を設定する方法の簡単な概要を示します。

CompletionService<YourCallableImplementor> completionService = 
    new ExecutorCompletionService<YourCallableImplementor>(service);
    ArrayList<Future<YourCallableImplementor>> futures = new ArrayList<Future<YourCallableImplementor>>();
    for (String computeMe : elementsToCompute) {
        futures.add(completionService.submit(new YourCallableImplementor(computeMe)));
    }

次に、予想される結果の数を追跡し、次のように取得する必要があります。

try {
  int received = 0;
  while (received < elementsToCompute.size()) {
     Future<YourCallableImplementor> resultFuture = completionService.take(); 
     YourCallableImplementor result = resultFuture.get();
     received++; 
  }
} finally {
  service.shutdown();
}
4
fl0w

Runtimeクラスには、availableProcessors()というメソッドがあります。これを使用して、CPUの数を把握できます。プログラムはCPUにバインドされているため、使用可能なCPUごとに(最大で)1つのスレッドが必要になります。

3
Eric Petroelje