11

解決

質問

セキュリティフレームワークをコーディングしているときに、「プールするかしないか」という通常のジレンマに直面します。

基本的に、この質問は2つの「グループ」に分かれています。

  1. グループ1:SecureRandomの呼び出しnextBytes(...)が同期され、WebApp/マルチスレッドアプリのボトルネックになる可能性があるため

  2. グループ2:、、、、、 ...などMessageDigestの暗号サービスプロバイダー( ?のコストのため)SignatureCipherKeyFactorygetInstance()

あなたの意見は何ですか ?

そのような質問に対するあなたの習慣は何ですか?

2013年9月7日編集

私はついに自分で@QwerkyShareクラスをテストするのに時間をかけました、そして私は結果がかなり...驚くべきことに気づきました。

クラスには私の主な関心事が欠けていました:GenericObjectPoolStackObjectPoolのようなプール。

だから私は4つの選択肢すべてをテストするためにクラスを作り直しました:

  • 同期の要点を持つ単一の共有インスタンス
  • 各ループ内の新しいインスタンス(ダイジェストの作成をループの外にプルできる場合は興味がありません)要点
  • GenericObjectPool:要点
  • StackObjectPool:要点

1Mがプールで時間がかかりすぎたため、ループの数を100000に減らす必要がありました。

また、各ループの最後にを追加Thread.yield()して、負荷の形状を改善しました。

結果(累積実行時間):

  • メッセージダイジェスト
    • 新しいインスタンス:420秒
    • シングルインスタンス:550秒
    • StackObjectPool:800秒
    • GenericObjectPool:1900秒
  • KeyFactory
    • 新しいインスタンス:400秒
    • シングルインスタンス:350秒
    • StackObjectPool:2900秒
    • GenericObjectPool:3500秒
  • SecureRandom
    • StackObjectPool:1600秒
    • 新しいインスタンス:2300秒
    • GenericObjectPool:2300秒
    • シングルインスタンス:2800秒
  • 暗号
    • StackObjectPool:2800秒
    • GenericObjectPool:3500秒
    • シングルインスタンス:5100秒
    • 新しいインスタンス:8000秒

結論

MessageDigestとKeyFactoryの場合、プールはパフォーマンスキラーであり、同期のボトルネックがある単一のインスタンスよりもさらに悪いですが、SecureRandomとCipherに関しては非常に便利です。

4

2 に答える 2

6

100 スレッドに共有へのアクセスを許可し、MessageDigestそれぞれに 1,000,000 ハッシュを計算させると、私のマシンでは最初のスレッドが 70,160 ミリ秒で終了し、最後のスレッドが 98,748 ミリ秒で終了します。

スレッドが毎回の新しいインスタンスを作成する場合MessageDigest、最初のスレッドは 43,392 ミリ秒で終了し、最後の 58,691 ミリ秒で終了します。

編集:
実際、この例では、スレッドが 2 つしかないため、新しいインスタンスを作成する例の方が速く実行されます。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Share {

  final byte[] bytes = new byte[100];
  final MessageDigest sharedDigest;
  final ExecutorService pool;
  int threads = 100;

  Share() throws NoSuchAlgorithmException {
    sharedDigest = MessageDigest.getInstance("MD5");
    pool = Executors.newFixedThreadPool(threads);
  }

  void go() {

    for (int i=0; i<threads; i++) {
      pool.execute(new Runnable() {
        public void run() {
          long start = System.currentTimeMillis();
          for (int i=0; i<1000000; i++) {
            /*
            synchronized (sharedDigest) {
              sharedDigest.reset();
              sharedDigest.update(bytes);
              sharedDigest.digest();
            }*/
            try {
              MessageDigest digest = MessageDigest.getInstance("MD5");
              digest.reset();
              digest.update(bytes);
              digest.digest();
            } catch (Exception ex) {
              ex.printStackTrace();
            }
          }
          long end = System.currentTimeMillis();
          System.out.println(end-start);
          pool.shutdown();
        }
      });
    }

  }

  public static void main(String[] args) throws Exception {
    Share share = new Share();
    share.go();
  }

}
于 2012-12-17T12:45:48.140 に答える
0

このテストはキャッシングを支持しているようです

long t0 = System.currentTimeMillis();
byte[] bytes = new byte[100];
MessageDigest md = MessageDigest.getInstance("MD5");
for(int i = 0; i < 1000000; i++) {
    //MessageDigest md = MessageDigest.getInstance("MD5");
    md.reset();
    md.update(bytes);
    md.digest();
}
System.out.println(System.currentTimeMillis() - t0);

md がループの外側にある場合は 579 を出力し、ループの内側にある場合は - 953 を出力します。

于 2012-12-17T11:26:52.260 に答える