1

私は(Javaでの)並列/並行プログラミングに頭を悩ませようとしていて、これまで読んでいたチュートリアルのいずれにも含まれていないように見えるいくつかの基本に夢中になっています。

「マルチスレッド」または「並列/並行プログラミング」について話すとき、それは私たちが大きな問題を抱えてそれを多くのスレッドに広げていることを意味しますか、それとも最初にそれをより小さなサブ問題に明示的に分解して渡しますか?独自のスレッドに対する各サブ問題?

たとえば、がEndWorldHungerTask implements Runnableあり、タスクがいくつかの大きな問題を達成するとします。その目的を達成するために、それはいくつかの本当に重い持ち上げをしなければなりません、例えば、1億回:

public class EndWorldHungerTask implements Runnable {

    public void run() {
        for(int i = 0; i < 100000000; i++)
            someReallyExpensiveOperation();
    }
}

これを「並行」または「マルチスレッド」にするために、これEndWorldHungerTaskをたとえば100個のワーカースレッドに渡します(100個のワーカーのそれぞれがJVMによって、いつアクティブになり、次の反復/someReallyExpensiveOperation()呼び出しで作業するかを指示されます)。 )、または100人のワーカーのそれぞれがループ/実行する作業のさまざまな部分を反復処理するように、手動/明示的にリファクタリングしますか?どちらの場合も、100人のワーカーのそれぞれが100万回しか反復していません。

しかし、最初のパラダイムでは、Javaは各スレッドにいつ実行するかを指示しています。2つ目では、開発者は事前に手動で(コード内で)問題を分割し、各サブ問題を新しいスレッドに割り当てる必要があります。

私は、Javaの土地で「通常行われている」方法を尋ねていると思います。そして、この問題のためだけでなく、一般的に。

4

4 に答える 4

1

私は、Javaの土地で「通常行われている」方法を尋ねていると思います。そして、この問題のためだけでなく、一般的に。

これは、目前のタスクに大きく依存します。

Javaの標準的なパラダイムは、作業を自分でチャンクに分割する必要があるというものです。これらのチャンクを複数のスレッド/コアに分散することは別の問題であり、そのためのさまざまなパターン(キュー、スレッドプールなど)が存在します。

興味深いことに、複数のコアを自動的に利用してforループなどを並列で実行できるフレームワーク(OpenMPなど)が存在します。しかし、私はJava用のそのようなフレームワークを知りません。

最後に、作業の大部分を実行する低レベルのライブラリが複数のコアを利用できる場合があります。このような場合、上位レベルのコードはシングルスレッドのままで、マルチコアハードウェアの恩恵を受けることができる場合があります。一例として、 MKLを裏で使用した数値コードがあります。

于 2012-04-27T18:15:05.137 に答える
1

「マルチスレッド」または「並列/並行プログラミング」について話すとき、それは私たちが大きな問題を抱えてそれを多くのスレッドに広げていることを意味しますか、それとも最初にそれをより小さなサブ問題に明示的に分解して渡しますか?独自のスレッドに対する各サブ問題?

これは問題に大きく依存していると思います。同じコードを使用して数千回または数百万回呼び出す同じタスクがある場合があります。これがExecutorSerivce.submit()パターンのタイプです。ファイルから数百万行があり、各行でいくつかの処理メソッドを実行しています。これは「多くのスレッドに広がる」タイプの問題だと思います。これは、単純なスレッドモデルで機能します。

しかし、問題空間が多数の不均一なタスクで構成されている場合もあります。バックグラウンドキープアライブを処理するために単一のスレッドを生成する場合もあれば、作業のキューを処理するためにあちこちにスレッ​​ドプールを生成する場合もあります。通常、問題の範囲が大きいほど、並行性モデルが複雑になり、使用されるプールとスレッドのタイプが増えます。これはあなたの「小さなサブ問題に分解する」タイプだと思います。

これを「並行」または「マルチスレッド」にするために、このEndWorldHungerTaskをたとえば100個のワーカースレッドに渡します(100個のワーカーのそれぞれがJVMによって、いつアクティブになり、次の反復で作業するかを指示されます/ someReallyExpensiveOperation()呼び出し)、または100人のワーカーのそれぞれがループ/実行する作業のさまざまな部分を反復処理するように手動/明示的にリファクタリングしますか?どちらの場合も、100人のワーカーのそれぞれが100万回しか反復していません。

あなたの場合、1セットのスレッドコードで(アナロジーを使用して)世界の飢餓を解決する方法がわかりません。私はあなたが「それをより小さなサブ問題に分解する」必要があると思います。これは私が上で説明した後者の場合に対応します:異なるコードを実行する一連のスレッド全体。一部のサブソリューションはスレッドプールで実行でき、一部は個別のスレッドで実行され、それぞれが個別のコードを実行します。

私は、Javaの土地で「通常行われている」方法を尋ねていると思います。そして、この問題のためだけでなく、一般的に。

「通常」は、問題とその複雑さに大きく依存します。私の経験では、私は通常、ExecutorService可能な限り構成を使用します。しかし、適切なサイズの問題があると、さまざまなスレッドプール、Springタイマースレッド、カスタムの1回限りのスレッドタスク、生産者/消費者モデルなどが発生します。

于 2012-04-27T18:15:06.520 に答える
0

通常、各スレッドで1つのタスクフォームを最初から最後まで実行する必要があります。タスクを半分完了したままにして、そのスレッドでの実行を停止し、別のスレッドを「呼び出して」ジョブを終了しても何も得られません。Javaはもちろん、この種のスレッド同期用のツールを提供しますが、タスクが完了するために別のタスクに依存している場合に実際に使用されます。別のスレッドがタスクを完了するためではありません。

ほとんどの場合、いくつかのタスクで構成される大きな問題が発生します。このタスクを同時に実行できる場合は、スレッドを生成してこのタスクを実行するのが理にかなっています。スレッドの作成に関連するオーバーヘッドがあるため、すべてのタスクがシーケンシャルであり、他のタスクが終了するのを待たなければならない場合、メインスレッドをブロックしないように、1つのスレッドだけで、複数のスレッドを生成することはまったく有益ではありません。 。

于 2012-04-27T18:14:50.940 に答える
0

「マルチスレッド」<>「並列​​/並行プログラミング」。

マルチスレッドアプリは、プリエンプティブマルチタスカーの高いI/Oパフォーマンスを利用するように作成されることがよくあります。例としては、Webクローラー/ダウンローダーがあります。マルチスレッドクローラーは、CPUコアが1つしかないボックスで実行している場合でも、通常、シングルスレッドバージョンよりも大幅に優れています。サイトアドレスを取得するDNSクエリのアクション、サイトへの接続、ページのダウンロード、ディスクファイルへの書き込みはすべて、CPUをほとんど必要としないが、多くのIO待機を必要とする操作です。したがって、これらの避けられない待機の多くは、多くのスレッドによって並行して実行できます。DNSクエリが着信すると、HTTPクライアントが接続するか、ディスク操作が完了すると、DNSクエリを要求したスレッドが準備完了/実行され、次の操作に進むことができます。

このため、アプリの大部分は、主にマルチスレッドとして作成されています。そのため、私がこれを書いているボックスには、98のプロセス(うち94は複数のスレッドがあります)、1360のスレッド、3%のCPU使用率があります-CPUの作業をコア間で分割することとはほとんど関係ありません-それは主にIOに関するものですパフォーマンス。

並列/並行プログラミングは、実際には複数のCPUコアで実行できます。コア間で分散するために大きなパッケージに分解できるCPUを集中的に使用する作業を行うアプリの場合、コアの数に近づくスピードアップ係数は注意して可能です。

当然のことながら、多少のブリードオーバーがあります。I/ OバウンドのWebクローラーは、割り込み/ドライバーのオーバーヘッドが全体的なパフォーマンスに与える影響が小さいという理由だけで、コアが多いボックスでパフォーマンスが向上する傾向がありますが、それほど向上することはありません。

作物が成長するのを全員が待っている場合、EndWorldHungerタスクに利用できるワーカーの数は関係ありません。

于 2012-04-27T20:19:04.360 に答える