3

アプリケーションにカウンターのマップ (Map など) を実装する必要があります。ただし、この構造体は複数のスレッドからアクセスされることになっています。

適切な解決策ではないようConcurrentHashMap<Key, Long>ですよね?

代わりに考えましConcurrentHashMap<Key, AtomicLong>た。

しかし、問題があります。インクリメントのリクエストは均等に分散されません。このデータ構造に対するすべてのインクリメント リクエストの最大 95% を占める最も一般的なキーはほとんどありません。

私が理解している限り、これは単一AtomicLongインスタンスへの同時アクセスにつながり、多くのロックが発生して効率が多少低下します。

質問 1:もっと良い解決策はありAtomicLongますか?

質問 2:構造を定期的に (おそらく 1 分ごとに) ディスクに永続化し、その「実際の」状態を永続化したい (最近の更新はすべて解決されていますか?) - 最も簡単な方法は何ですか?

4

2 に答える 2

4

AtomicLong が内部でロックを使用していると思われる理由は何ですか? それは真実ではありません。ほとんどの場合、CAS操作に基づいて構築されています。私のアドバイスは、AtomicLong で実装し、後で実装をプロファイリングすることです。カウンターがボトルネックになる場合 (その場合のみ)、他の実装に置き換えることを検討してください。

「私たちは小さな効率を忘れるべきです。たとえば、約 97% の確率で: 時期尚早の最適化はすべての悪の根源です」 - Donald Knuth

状態の永続性に関して、最も簡単な方法は、マップをシリアル化することです。

ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(map);
objOut.close();
于 2013-08-10T05:44:24.750 に答える
4

まず、ここで「時期尚早の最適化」のリスクがあります。心配している同時実行性のホットスポット/ボトルネックが重要ではない可能性は十分にあります。

そうは言っても:

同時実行性のホットスポットが大きな問題でない限り、 AConcurrentHashMap<Key, AtomicLong>は適切なオプションのように思えます。ConcurrentHashMapは、マップの同時実行性に関する問題を大幅に回避する必要がありAtomicLong、単一のカウンターで極端な競合が発生しない限り、優れたパフォーマンスを提供します。

より良い解決策はありますか?おそらく、AtomicLong の代わりに、増分の短い累積などを可能にするより良いデータ型ですか?

それはうまくいくかもしれません。(たとえば、各スレッドは独自の (非並行) マップを持ち、 ではなくLongまたは非同期のカスタムホルダー クラスを使用できます。)longAtomicLong

ただし、これを行うことの欠点は次のとおりです。

  • メモリ使用量が大幅に増加する可能性があります。
  • 複数のマップを 1 つに結合して最終的なカウントを取得するという追加のオーバーヘッドが発生します。そのステップには、シリアル計算が含まれる可能性が最も高いでしょう。

全体として、膨大な数のコアと非常に高いカウント率がない限り、これによりパフォーマンスが向上した場合は驚くでしょう.

構造を定期的に (おそらく毎分) ディスクに永続化し、その「実際の」状態を永続化したい (最近の更新はすべて解決されていますか?) - 最も簡単な方法は何ですか?

それを行う最も簡単な方法は、固執している間はすべてを停止することです。

それが受け入れられない場合は、次のようなことを行う必要があります。

  1. 固執することを決定します。
  2. 新しいConcurrentHashMap<Key, AtomicLong>インスタンスを作成します。
  3. カウントを累積できるように、既存のマップを新しいマップにアトミックに置き換えます。
  4. 古いマップを保持します。
  5. 古いマップを繰り返し、各キーのカウントを新しいマップにアトミックに転送します。
  6. 古い地図を破棄します。
于 2013-08-10T05:57:34.170 に答える