12

私は、メモリと計算負荷の両方が高いプロジェクトに取り組んでいます。実行の大部分は、FixedThreadPool. 要するに; 複数のリモート ロケーションから (URL 接続を使用して) データをフェッチし、分析対象のオブジェクトをデータに取り込むための 1 つのスレッドと、これらオブジェクトを選択して分析を実行するn 個のスレッドがあります。編集:以下のコードを参照してくださいBlockingQueue

現在、このセットアップは、OpenSUSE 11.3 を実行している私の Linux マシンで魅力的に機能しますが、同僚が Win7 を実行している非常によく似たマシンでそれをテストしており、キューのポーリングでタイムアウトのカスタム通知を取得しています (以下のコードを参照)。私は彼女のマシンでプロセッサの使用状況を監視しようとしてきましたが、私のマシンでは意図したとおりにプロセッサの使用率が上限に達している間、ソフトウェアは CPU の 15% を超えないようです。

私の質問は、これはキューの「飢餓」の兆候でしょうか? プロデューサースレッドが十分なCPU時間を取得していない可能性がありますか? もしそうなら、プール内の特定のスレッドに高い優先度を与えるにはどうすればよいですか?

更新: 私は問題を特定しようとしてきましたが、喜びはありませんでした...しかし、いくつかの新しい洞察を得ました。

  • JVisualVM を使用してコードの実行をプロファイリングすると、非常に特異な動作が示されます。メソッドは、CPU 時間の短いバーストで呼び出され、その間に数秒間進行がありません。これは、何らかの形で OS がプロセスにブレーキをかけていることを意味します。

  • ウイルス対策およびバックアップ デーモンを無効にしても、問題に大きな影響はありません。

  • タスク マネージャー (ここで推奨) を使用して java.exe (唯一のインスタンス) の優先度を変更しても、何も変更されません。(そうは言っても、Javaに「リアルタイム」の優先順位を与えることはできず、「高い」プライオリティに満足する必要がありました)

  • ネットワークの使用状況をプロファイリングすると、データの出入りの良好な流れが示されるので、それがボトルネックではないと推測しています (プロセスの実行時間のかなりの部分を占めていますが、私はすでに知っており、 Linux マシンで得られるもの)。

Win7 OS がプロジェクトの CPU 時間をどのように制限しているかについてのアイデアはありますか? それがOSでない場合、何が制限要因になる可能性がありますか? もう一度強調したいのですが、マシンは同時に他の計算集約的な処理を実行しておらず、私のソフトウェア以外の CPU にはほとんど負荷がかかっていません。これは私を夢中にさせています...

編集: 関連するコード

public ConcurrencyService(Dataset d, QueryService qserv, Set<MyObject> s){

    timeout = 3;
    this.qs = qserv;
    this.bq = qs.getQueue();
    this.ds = d;
    this.analyzedObjects = s;
    this.drc = DebugRoutineContainer.getInstance();
    this.started = false;

    int nbrOfProcs = Runtime.getRuntime().availableProcessors();
    poolSize = nbrOfProcs;
    pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
    drc.setScoreLogStream(new PrintStream(qs.getScoreLogFile()));
}

public void serve() throws InterruptedException {
    try {
        this.ds.initDataset();
        this.started = true;
        pool.execute(new QueryingAction(qs));
        for(;;){
            MyObject p = bq.poll(timeout, TimeUnit.MINUTES);

            if(p != null){
                if (p.getId().equals("0"))
                    break;

                pool.submit(new AnalysisAction(ds, p, analyzedObjects, qs.getKnownAssocs()));
            }else 
                drc.log("Timed out while waiting for an object...");

        }

      } catch (Exception ex) {
            ex.printStackTrace();
            String exit_msg = "Unexpected error in core analysis, terminating execution!";

      }finally{
            drc.log("--DEBUG: Termination criteria found, shutdown initiated..");
            drc.getMemoryInfo(true);    // dump meminfo to log

            pool.shutdown();

            int mins = 2;
            int nCores = poolSize;
            long    totalTasks = pool.getTaskCount(), 
                    compTasks = pool.getCompletedTaskCount(),
                    tasksRemaining = totalTasks - compTasks,
                    timeout = mins * tasksRemaining / nCores;

            drc.log("--DEBUG: Shutdown commenced, thread pool will terminate once all objects are processed, " +
                        "or will timeout in : " + timeout + " minutes... \n" + compTasks + " of " +  (totalTasks -1) + 
                        " objects have been analyzed so far, " + "mean process time is: " +
                        drc.getMeanProcTimeAsString() + " milliseconds.");

            pool.awaitTermination(timeout, TimeUnit.MINUTES);
      }

}

このクラスQueryingActionは、指定されたオブジェクトでRunnableデータ取得メソッドを呼び出してから. このクラスは、 の 1 つのインスタンスに対してすべての数値処理を行います。QueryServiceBlockingQueueAnalysisActionMyObject

4

8 に答える 8

3

プロデューサー スレッドのソース データの取得/読み込み速度が十分ではないと思われます。これは CPU の不足ではなく、IO 関連の問題である可能性があります。(BlockingQueue でタイムアウトが発生する理由がわからない)

追加されたタスクの数やキューの長さなどを定期的に (たとえば 5 ~ 15 秒ごとに) ログに記録するスレッドを持つ価値があるかもしれません。

于 2011-12-19T11:03:55.037 に答える
3

したがって、私が問題を正しく理解していれば、データをフェッチするスレッドが 1 つと、フェッチしたデータを分析するスレッドがいくつかあることになります。あなたの問題は、スレッドが一緒に実行され、プロセッサを最大限に活用するために正しく同期されていないことです。

単一のプロデューサーと複数のコンシューマーに関する典型的なプロデューサーとコンシューマーの問題があります。代わりに、リソースが利用可能になるのを常に待ってから実行する独立した消費者スレッドをいくつか持つように、コードを少し作り直すことをお勧めします。このようにして、最大のプロセッサー使用を保証します。

コンシューマ スレッド:

while (!terminate)
{
    synchronized (Producer.getLockObject())
    {
        try
        {
            //sleep (no processing at all)
            Producer.getLockObject().wait(); 
        }
        catch (Exceptions..)
    }

    MyObject p = Producer.getObjectFromQueue(); //this function should be synchronized

    //Analyse fetched data, and submit it to somewhere...   
}    

プロデューサー スレッド:

while (!terminate)
{
    MyObject newData = fetchData(); //fetch data from remote location

    addDataToQueueu(newData); //this should also be synchronized

    synchronized (getLockObject())
    {
        //wake up one thread to deal with the data
        getLockObject().notify();
    }
}

このようにして、スレッドが常に有用な作業を実行しているか、スリープ状態にあることがわかります。これは、例示するための単なるドラフト コードです。ここで詳細な説明を参照してください: http://www.javamex.com/tutorials/wait_notify_how_to.shtml およびここ: http://www.java-samples.com/showtutorial.php?tutorialid=306

于 2012-02-01T15:22:02.240 に答える
1

問題は誰が貴重なリソースを取得するかを決定する問題ではないため、優先度は役に立ちません。リソースの使用量は最大ではありません。プロデューサー スレッドが十分な CPU 時間を取得できない唯一の原因は、実行する準備ができていない場合です。問題は問題ではないため、優先度は役に立ちません。

マシンにはいくつのコアがありますか? プロデューサ スレッドがフル スピードで実行されている可能性がありますが、まだ十分な CPU がありません。プロデューサーが I/O バウンドである可能性もあります。

于 2011-12-19T11:06:08.397 に答える
1

URL接続とは、ローカルとリモートのどちらを指しますか? ネットワーク速度がプロデューサーの速度を低下させている可能性があります

于 2011-12-20T10:42:59.690 に答える
1

プロデューサー スレッドをプールから分離してみてください (つまり、個別のスレッドを作成し、Threadプールの現在の容量が -1 になるように設定します) setPriority。優先順位がパフォーマンスのこのような違いを説明することはめったにありませんが、何が起こるかを見てください。

于 2011-12-19T11:08:56.173 に答える
1

だから、いじくり回したり、コードと格闘したり、他の種類の苦しみを何週間も経験した後、私は突破口、「明確な瞬間」があったと思います...

私は、プログラムが私の Linux マシンで同じように遅い動作を示し、実際に問題のある Win-7 マシンでフルスロットルで実行できることを示すことができました。問題の核心は、以前のクエリの結果を保存するために使用されるシステム/キャッシュ ファイルの何らかの破損であり、全体的に分析が高速化されているようです。皮肉なことに、この場合、分析が極端に遅くなる理由のように見えました。振り返ってみると、(オッカムのカミソリのように) 知っておくべきでした...

破損がどのように発生するのかはまだわかりませんが、少なくとも別の OS に関連していない可能性があります。ただし、私のマシンのシステム ファイルを使用すると、Win7 ホストでの出力が最大約 40% しか増加しません。プロセスをさらにプロファイリングすると、奇妙なことに、Win7 での GC アクティビティが大幅に増加していることが明らかになりました。これは明らかに、数値処理に多くの CPU 時間を費やしたようです。Giving-Xmx2gは過剰なガベージ コレクションを処理し、プロセスの CPU 使用率は 95 ~ 96% まで上昇し、スレッドはスムーズに実行されます。

元の質問に答えたので、全体的な Java の応答性は Linux 環境の方が確実に優れていると言わざるを得ません。ヒープ メモリを割り当てなくても、バックグラウンドで大規模な分析を実行しているときに簡単にマルチタスクを実行できます。Win-7 では物事はスムーズではありません。分析がフルスピードで開始されると、GUI のサイズ変更が大幅に遅くなります。

すべての返信に感謝します。部分的に誤解を招く問題の説明で申し訳ありません。私は、自分の能力を最大限に発揮してデバッグ中にわかったことを共有しただけです。とにかく、賞金は Peter Lawrey に行くと思います。なぜなら、彼は早い段階で I/O の問題を指摘し、ロガー スレッドに関する彼の提案が最終的に私を答えに導いたからです。

于 2012-02-02T18:10:56.020 に答える
0

申し訳ありませんが、実際には答えではありませんが、コメント内に収まりませんでしたが、それでも読む価値があると思います:

  • まあ、私はJAVAフレンドリーではありません
  • しかし、私は最近、USB を介したマシン制御用の C++ プロジェクトで同じ問題を抱えています。
  • XP または W2K では、2 つ以上のコア マシンで 24 時間年中無休の運用を何ヶ月も行うことができます。
  • W7 では、十分に強力なマシンはすべて正常に動作しますが、明らかな理由もなく数秒間フリーズすることがあります (数時間に約 1 回)。
  • W7 と比較的弱いマシン (2 コア 1.66GHz T2300E ノートブック) では、スレッドがしばらくの間フリーズし、再び実行されて、USB/WIN/App FIFO がアンダーフローまたはオーバーフローし、通信が崩壊します ...
    • 何もブロックされていないように見えますが、W7 シェデュラーが適切なスレッドに CPU を割り当てないことがあります。
    • USBドライバ(JUNGO)通信でつぼみがフリーズすると思っていたのですが、そうではありません 計測してみるとフリーズでもOK
    • フリーズは 1 分に 1 回約 6 ~ 15 秒でした。
    • スレッドループにいくつかの安全スリープを追加した後、フリーズは約0.5秒に短縮されました
    • しかし、まだそこに
    • アプリがFIFOをアンダー/オーバーフローしない場合でも、Windows USBドライバー側は行います(数ミリ秒の間、毎分数回)
  • exe/スレッドの優先度とクラスの変更は、W7 のパフォーマンスには影響しません (XP では、W2K は正常に動作します)。

ご覧のとおり、おそらく同じ問題を抱えているようです。私の場合:

  • I / O関連ではありません(USBスレッドをデバイスのシミュレーションに置き換えると、同様に動作します)
  • タイム クリティカルなコードに Sleep を追加すると、多くの場合に役立ちます
  • スレッド数が少ない場合にもエラーが発生する[2 高速 (17ms) + 1 低速 (250ms) + アプリ コード = 4]
  • 私の W7 低速マシンでの CPU 消費率も 100% ではなく約 95% ですが、どこでもスリープしているので問題ありません。
  • 私のアプリは約 40 ~ 100 MB のメモリを使用しますが、CPU の計算が必要です ...
    • しかし、はるかに遅いマシンで安全に実行できるほどではありません
    • ただし、USB ドライバー接続と複数デバイスのサポートのために、少なくとも 2 つのコアが必要です。
  • 私の次のステップは、実行時間のログ記録/分析を追加して、何が起こっているかをより詳細に確認することです
  • また、送信/受信スレッドを少し書き直して、それが役立つかどうかを確認します

何か新しい/便利なことを学ぶと、それが追加されます。

于 2013-11-21T08:27:23.363 に答える
0

それが2つのユニットのコアの違いであるため、OS固有の問題だと思います。より具体的には、何かがリモート接続を介して到着するデータを遅くしています。

WiresharkNetworxなどのトラフィック分析ツールを見つけて、Win PC を抑制しているものがないかどうかを調べます。おそらく、何らかのレート キャップが設定されたプロキシを経由しているのでしょう。

于 2012-02-01T11:44:26.893 に答える