質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

NetBeans

NetBeansは Java、HTML5、PHP、C/C++のアプリケーションのフレームワーク、もしくは統合開発環境(NetBeans IDE)の両方を指します

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

並列処理

複数の計算が同時に実行される手法

Q&A

解決済

2回答

7049閲覧

Javaでの並列計算でCPUの稼働率が低くなってしまう

syncret

総合スコア13

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

NetBeans

NetBeansは Java、HTML5、PHP、C/C++のアプリケーションのフレームワーク、もしくは統合開発環境(NetBeans IDE)の両方を指します

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

並列処理

複数の計算が同時に実行される手法

0グッド

3クリップ

投稿2017/09/29 08:51

###前提・実現したいこと
Javaで並列数値計算を行うプログラムを書いています。
反復的に同じ量を計算するのですが、各反復の結果に応じてパラメータを変化させ、それを使ってまた同じ計算をするというプログラムです。
並列計算は、その一回一回の計算を行う時に毎回行っており、各スレッドで別々の数値データを読み込んで計算を行います。

これをワークステーション(詳細は下記)でCPU稼働率100%弱で効率的に計算したいです。

###発生している問題・エラーメッセージ

100スレッド並列で計算するプログラムになっているのですが、実行後しばらくは
想定通り稼働率100%で動いてくれるのですが、途中からCPUが平均して10%程度しか利用されません。
尚、1回の反復で20分かかる程度の重さの計算です。また並列するスレッドの数を30程度やそれ以下に減らしても同様です。

###該当のソースコード

Java

1 2//重要でない部分を簡略化したコードでお示ししています 3public class Main{ 4 static int threadNum = 100; 5 6 public static void main(String[] args){ 7 ... 8 // iterationしてパラメータxを更新する 9 for(int i=0;i<iterMax;i++){ 10 x = iterete(x); 11 } 12 } 13 14 15 public static double iterate(double x){ 16 17 double xnew = 0;//update後のパラメータ 18 List<int[]> sampleSet = new ArrayList<int[]>(); 19 ...//sampleSet.get(i)はi番目のスレッドが担当するデータ番号の組が入るようにする。sampleSet.size()=threadNum 20   21 //multi threadで計算する部分 22 ExecutorService threadpool = Executors.newCachedThreadPool(); 23 List<Future<Double>> futures = new ArrayList<>(); 24 List<Double> result = new ArrayList<Double>(); 25 for(int i = 0; i < threadNum;i++){ 26   futures.add(threadpool.submit(new EachThreadCal(sampleSet.get(i),x))); 27 } 28 29 try{ 30 threadpool.shutdown(); 31 for(int i = 0; i < threadNum; i++){ 32 //結果の取得 33 result.add(futures.get(i).get()); 34 } 35 36 for(Double s: result){ 37 //結果の表示 38 System.out.println(s); 39 xnew += s;//パラメータは計算結果の平均値、というプログラムなので全部足して後で割ることにしています 40 } 41 42 }catch(InterruptedException | ExecutionException e){ 43 e.printStackTrace(); 44 threadpool.shutdown(); 45 } 46 47 return xnew/sampleNum; 48 49 } 50 51} 52 53class EachThreadCal implements Callable<Double>{ 54 private int[] samples;//担当するサンプルの番号の配列が入る 55 private double x;//前回のパラメータの値が入る 56 57 public EachThreadCal(int[] samples,double x){ 58 this.samples = samples; 59 this.x = x; 60 } 61 62 @Override 63 public Double call() throws Exception {//個々の計算 パラメータxを更新してxnewを計算する部分 64 double xnew = 0; 65 for(int i=0;i<samples.length;i++){//担当するサンプルデータに対してパラメータxnewを計算して全部足す 66 xnew += ...//samples.get(i)番目のデータ(外部から読み込む)とパラメータxを使ってxnew を計算する 67 } 68 69 return xnew; 70 } 71}

###試したこと
スレッドの数threadNumを変えて試してみましたが改善しませんでした。
WindowsのタスクマネージャからCPU優先度を最大にしても改善しませんでした。
CPU以外のリソースも不足しているわけではないようです。

###補足情報(言語/FW/ツール等のバージョンなど)
【環境】
Product Version: NetBeans IDE 8.1 (Build 201510222201)
Java: 1.8.0_91; Java HotSpot(TM) 64-Bit Server VM 25.91-b14
Runtime: Java(TM) SE Runtime Environment 1.8.0_91-b14
System: Windows 10 version 10.0 running on amd64; MS932; ja_JP (nb)
Processor: Intel(R) Xeon(R) CPU E5-2687W v4 @ 3.00 GHz, 3001Mhz, 12 core, 24 logical processor × 2
メモリ:128 GB

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2017/09/29 13:28

タスク実行のスケジュール直後に、threadpool.shutdown();を実行しているのはなぜですか?
syncret

2017/10/02 05:54 編集

Stripe様 精査くださりありがとうございます。tryの中のどこかでやればよいと理解していたので(よくわかっていません)そうしていました。正しくはどこに挿入すればよいでしょうか?尚、try{}の内部の最後の位置に移動してみましたが、それでは解決しませんでした。引き続き、よろしくお願いいたします。
yohhoy

2017/10/03 03:53 編集

shutdownメソッドの呼び出し位置自体は問題ではないと思います。同メソッドの挙動は「それ以降の新規タスク受入を終了/受入済みタスクには影響なし」です。ただ、一般的にはfinally節にでも書いておいたほうが良い気はしますが。
yohhoy

2017/10/03 04:05 編集

「1回の反復で20分かかる程度の重さの計算」とありますが、この計算時間は入力データによらず(ほぼ)一定でしょうか?アルゴリズム上の枝刈処理などで早々に処理終了するタスクもあるのでしょうか?
syncret

2017/10/03 04:04

yohhoy様 ご教示いただきありがとうございます。各スレッドは同じステップ数のシミュレーションを行っているだけなので多少のばらつきはありますがほぼ一定と考えてよろしいかと思います。引き続き、よろしくお願いいたします。
yohhoy

2017/10/03 04:07 編集

newFixedThreadPool(n)でn=24または48とすると、CPU利用率遷移と総処理時間は変わりますか?
Stripe

2017/10/03 12:33

「このメソッドは、以前に送信されたタスクが実行を完了するのを待機しません。これを実行するには、awaitTerminationを使ってください。」と、shutdown()のリファレンスに書いてますけどね。
guest

回答2

0

ベストアンサー

回答ではありませんが。

1.Java起動オプションを教えてもらえますか?特にXmx, Xms。
→物理メモリが大きくてもXmxが無指定の場合、物理メモリの1/4しか使用されません。
→Xmsが小さい場合、ヒープ拡張が多発します。

2.Runtime.getRuntime().availableProcessors() の実行結果が全CPU全コア数の合計と一致しますか?(HyperThreadingがONであればそれを含めて)
→「logical processor × 2」とありますが、デュアルCPUのことでしょうか?
→デュアルCPUの場合プロセッサ間通信がボトルネックになることがあります。

3.CPUやマザーボードの温度を測ることはできますか? Thermal Throttling に触れていませんか?
→Thermal Throttling を超えた場合、一時的にクロック数を落とされてしまいます。
こちらのようなツールをインストールすることは可能ですか?

4.以下のプログラムを同じJava起動オプションで実行した場合、CPU使用率が100%になりますか?

Java

1public static void main(String... args){ 2 int vcpu = Runtime.getRuntime().availableProcessors(); 3 System.out.println("vCPU: " + vcpu); 4 ExecutorService service = Executors.newFixedThreadPool(vcpu); 5 List<Future<Double>> futures = new ArrayList<>(); 6 for(int i = 0; i < 100000; i++){ 7 futures.add(service.submit(() -> IntStream.range(1, 100000).mapToDouble(Math::sin).sum())); 8 } 9 service.shutdown(); 10 System.out.println("dummy: " + futures.stream().mapToDouble(future -> { 11 try{ return future.get(); }catch(Exception e){ return 0.0d; } 12 }).sum()); 13}

■余談
「100スレッド並列で計算するプログラムになっているのですが」とありますが、100スレッド並列で計算しているわけではありません。

投稿2017/10/04 05:47

mosa

総合スコア218

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2017/10/05 01:42 編集

newCachedThreadPool()はワーカスレッド数上限無しのThreadPoolExecutorを返すため、結果的に 100タスク投入=100スレッド並列計算 になっているかと思います。 http://d.hatena.ne.jp/masa_to/20110306/1299423229
mosa

2017/10/05 03:15

すみません。そのとおりですね。 正しくは「100スレッドが同時に計算処理されるわけではありません」ですね。
syncret

2017/10/11 11:18

mosa様 ご丁寧に検討下さりありがとうございました。指摘いただいた点を調べたところどうやらXmxの指定が小さすぎたことが原因のようで、無事ちゃんと動くようになりました。この度はありがとうございました。
guest

0

newCachedThreadPool は可変個スレッドなので、コンテキストスイッチにコストが掛かってるんじゃないかと思います。newFixedThreadPool(threadNum) だとどうなりますか?

投稿2017/09/29 09:16

mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2017/09/29 13:17

コンテキストスイッチのコストでCPU使用率が上がることはあれど、下がることはないのでは?
mattn

2017/09/29 15:05

CPU の飽和状態を見ながらスレッド数を調整するので期待以上にスレッドが溢れコンテキストスイッチ時のオーバーヘッドの方が大きくなり CPU が遊んでるんじゃないかと予想していいます。
Stripe

2017/09/29 15:34

CPU使用率を計測する際、コンテキストスイッチのオーバーヘッド分は計測されないんですか? 今回、CPU使用率が100%付近から10%付近まで落ちるそうですが、この時90%がコンテキストスイッチのオーバーヘッドであると言うことですか?
mattn

2017/09/30 11:51

いま気付きましたが、↑に書かれている shutdown が原因ぽいですね。一番最初に終了したタスクが shutdown を実行する事で次のアサインがされてないのでしょうね。
syncret

2017/10/02 05:56

mattn様 Stripe様 ご検討下さりありがとうございます。newFixedThreadPool(threadNum)も試してみましたが、解決しないようです。shutdownについては上記に追記いたしました。引き続き、よろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問