问题描述
- MessageDigest =>根据需要经常创建新实例
- KeyFactory =>使用单个共享实例
- SecureRandom =>使用
- Cipher =>使用
- MessageDigest => create new instances as often as needed
- KeyFactory => use a single shared instance
- SecureRandom => use a StackObjectPool
- Cipher => use a StackObjectPool
我在编写安全性框架时遇到常规困境:要汇集或不汇集
I face a regular dilemna while coding security frameworks : "to pool or not to pool"
基本上这个问题分为两个群组:
Basically this question is divided on two "groups" :
-
第1组:
SecureRandom
因为对nextBytes(...)
的调用是同步的,它可能成为WebApp /的瓶颈多线程应用程序
Group 1 :
SecureRandom
because the call tonextBytes(...)
is synchronized and it could become a bottleneck for a WebApp / a multi-threaded app
第2组:加密服务器副提供者如 MessageDigest
,签名
,密码
, KeyFactory
,...(由于 getInstance()
的费用?)
Group 2 : Crypto service providers like MessageDigest
, Signature
, Cipher
, KeyFactory
, ... (because of the cost of the getInstance()
?)
您有什么看法?
您对此类问题有什么习惯?
What are you habits on such questions?
我终于花时间测试@Qwerky 分享
我自己上课,我觉得结果很......令人惊讶。
I finally took time to test @Qwerky Share
class by myself and I find the result quite ... surprising.
课程缺乏我的主要关注:像或。
The class was lacking my main concern : Pools like GenericObjectPool or StackObjectPool.
所以我重新修改了这个类来测试所有4个选项:
So I've reworked the class to test all 4 alternatives :
- 同步的单个共享实例
- 每个循环内的新实例(我对此案不感兴趣当您可以在循环外拉动摘要时)
- GenericObjectPool:
- StackObjectPool:
- Single shared instance with synchronisation gist
- new instances inside each loops (I'm not interested in the case when you can pull the digest creation outside the loop) gist
- GenericObjectPool : gist
- StackObjectPool : gist
我不得不将循环次数降低到100000,因为1M花了太多时间使用池。
I had to lower the number of loops to 100000 since 1M was taking too much time with pools.
我还添加了一个 Thread.yield()
在每个循环结束时为负载提供更好的形状。
I also added a Thread.yield()
at the end of each loop to give the load a nicer shape.
结果(累积运行时):
- MessageDigest
- 新实例:420 s
- Single实例:550 s
- StackObjectPool:800 s
- GenericObjectPool:190 0 s
- MessageDigest
- new instances : 420 s
- Single instance : 550 s
- StackObjectPool : 800 s
- GenericObjectPool : 1900 s
- 新实例:400s
- 单个实例:350秒
- StackObjectPool:2900 s
- GenericObjectPool:3500 s
- new instances : 400s
- Single instance : 350 s
- StackObjectPool : 2900 s
- GenericObjectPool : 3500 s
- StackObjectPool:1600 s
- 新实例:2300 s
- GenericObjectPool:2300s
- 单个实例:2800 s
- StackObjectPool : 1600 s
- new instances : 2300 s
- GenericObjectPool : 2300s
- Single instance : 2800 s
- StackObjectPool:2800 s
- GenericObjectPool:3500 s
- 单个实例:5100秒
- 新实例:8000秒
- StackObjectPool : 2800 s
- GenericObjectPool : 3500 s
- Single instance : 5100 s
- new instances : 8000 s
对于MessageDigest和KeyFactory,池是执行杀手,甚至比具有同步的单个实例更糟糕瓶颈,而它们在SecureRandom和Cipher中非常有用
For MessageDigest and KeyFactory, pools are perf killers and are even worse than a single instance with a synchronisation bottleneck, whereas they are really usefull when it comes to SecureRandom and Cipher
推荐答案
如果给100个线程访问共享
MessageDigest
让他们计算1,000,000个哈希,然后在我的机器上第一个线程完成70,160毫秒,最后一个完成98,748毫秒。If you give 100 threads access to a shared
MessageDigest
and get them to calculate 1,000,000 hashes each then on my machine the first thread finishes in 70,160ms and the last finishes in 98,748ms.如果线程每次都创建一个
MessageDigest
的新实例,那么第一个线程将在43,492ms完成,最后一个58,691ms完成。If the threads create a new instance of
MessageDigest
each time, then the first thread finishes in 43,392ms and the last 58,691ms.编辑:
事实上,在这个例子中,只有两个线程,创建新实例的示例运行得更快。
In fact with this example, with only two threads the example creating new instances runs quicker.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(); } }
这篇关于要汇集还是不汇集java加密服务提供商的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!