私はJava数値最適化問題のクラスを解決するためのアプリケーション-より正確に言うと大規模な線形計画問題に取り組んでいます。単一の問題は、以下で解決できる小さなサブ問題に分割できます。並列。CPUコアよりも多くのサブ問題があるため、ExecutorServiceを使用して、ExecutorServiceに送信されるCallableとして各サブ問題を定義します。サブ問題を解決するには、ネイティブライブラリ(この場合は線形プログラミングソルバー)を呼び出す必要があります。
問題
最大44の物理コアと最大256gのメモリを備えたUnixおよびWindowsシステムでアプリケーションを実行できますが、大きな問題の場合、Windowsでの計算時間はLinuxでの計算時間よりも桁違いに長くなります。 Windowsはかなり多くのメモリを必要とするだけでなく、時間の経過に伴うCPU使用率は、最初の25%から数時間後には5%に低下します。 Windowsのタスクマネージャのスクリーンショットは次のとおりです。
観察
私が試したこと
質問
Windowsの場合、プロセスあたりのスレッド数はプロセスのアドレススペースによって制限されます( Mark Russinovich-Windowsの限界に挑む:プロセスとスレッド も参照)。これが限界に近づくと、これが副作用を引き起こすと考えてください(コンテキストスイッチのスローダウン、断片化...)。 Windowsの場合、作業負荷を一連のプロセスに分割しようとします。私が数年前に抱えていた同様の問題について、Javaライブラリを実装してこれをより便利に(Java 8)しました)、次のように見てください: 外部プロセス 。
ウィンドウのように聞こえるのは、しばらくの間メモリが変更されなかった後、ページファイルにメモリをキャッシュしているため、ディスク速度によってCPUがボトルネックになる理由です。
プロセスエクスプローラーでそれを確認し、キャッシュされているメモリの量を確認できます
このパフォーマンスの違いは、O.S。スレッドを管理します。 JVMはすべてのOSの違いを隠します。 this のように、それについて読むことができる多くのサイトがあります。しかし、違いがなくなるわけではありません。
Java 8+ JVMで実行していると思います。このため、ストリームおよび関数型プログラミング機能を使用することをお勧めします。関数型プログラミングは、小さな独立した問題が多数ある場合に非常に役立ちます順次実行から並列実行に簡単に切り替える必要があります。朗報は、ExecutorServiceのように、管理する必要のあるスレッドの数を決定するポリシーを定義する必要がないことです。たとえば、(- ここ ):
package com.mkyong.Java8;
import Java.util.ArrayList;
import Java.util.List;
import Java.util.stream.IntStream;
import Java.util.stream.Stream;
public class ParallelExample4 {
public static void main(String[] args) {
long count = Stream.iterate(0, n -> n + 1)
.limit(1_000_000)
//.parallel() with this 23s, without this 1m 10s
.filter(ParallelExample4::isPrime)
.peek(x -> System.out.format("%s\t", x))
.count();
System.out.println("\nTotal: " + count);
}
public static boolean isPrime(int number) {
if (number <= 1) return false;
return !IntStream.rangeClosed(2, number / 2).anyMatch(i -> number % i == 0);
}
}
結果:
通常のストリームの場合、1分10秒かかります。並列ストリームの場合、23秒かかります。 P7はi7-7700、16G RAM、Windows 10でテスト済み
したがって、Java)で関数プログラミング、ストリーム、ラムダ関数について読んで、コードで少数のテストを実装することをお勧めします(この新しいコンテキストで動作するように適応されています)。
システム統計を投稿していただけませんか?タスクマネージャーは、それが利用可能な唯一のツールである場合、いくつかの手掛かりを提供するのに十分です。タスクがIO=を待っているかどうかを簡単に確認できます。これは、あなたが説明した内容に基づいて犯人のように聞こえます。特定のメモリ管理の問題が原因であるか、ライブラリが一時データを書き込む可能性がありますディスクなどへ.
CPU使用率の25%と言っているのは、同時に動作しているコアの数が少ないということですか? (すべてのコアが時々動作するが、同時に動作しない場合があります。)システムで実際に作成されているスレッド(またはプロセス)の数を確認しますか?数は常にコアの数よりも大きいですか?
十分なスレッドがある場合、それらの多くはアイドル状態で何かを待っていますか? trueの場合、割り込みを試みる(またはデバッガーをアタッチする)ことで、それらが待機しているものを確認できます。