我正在实现一个线程池来处理大量市场数据馈送,并且对重用我的工作实例的策略有疑问,这些实例实现了可运行的提交到线程池执行。在我的例子中,我只有一种类型的工作人员接受一个字符串并对其进行解析以创建一个 Quote 对象,然后将其设置为正确的安全性。考虑到来自提要的数据量,每秒可能处理超过 1,000 个报价,我看到了两种创建提交到线程池的工作人员的方法。
第一个选项是每次从底层套接字中检索到一行时简单地创建一个新的 Worker 实例,然后将其添加到线程池中,线程池最终将在其 run 方法执行后被垃圾收集。但这让我开始思考性能,每秒实例化 1,0000 个 Worker 类的新实例是否真的有意义。本着与线程池相同的精神,人们是否知道拥有一个可运行的池或队列是否是一种常见模式,以便我可以回收我的工作人员以避免对象创建和垃圾收集。我看到这个实现的方式是在返回 run() 方法之前,Worker 将自己添加回可用 worker 队列,然后在处理新的馈送线时从中提取,而不是创建 Worker 的新实例。
从性能的角度来看,采用第二种方法对我有什么好处还是第一种方法更有意义?以前有人实现过这种模式吗?
谢谢 - 邓肯
最佳答案
我为此使用了我编写的名为 Java Chronicle 的库。它的设计目的是在不产生任何明显垃圾的情况下,每秒对一百万条报价进行持久化和排队。
我有一个演示 here它以每秒一百万条消息的速度发送带有纳秒计时信息的类似对象的引用,并且它可以在具有 32 MB 堆的 JVM 中发送数千万条消息,而不会触发甚至是次要收集。在我的 super 本上,90% 的时间往返延迟都小于 0.6 微秒。 ;)
from a performance perspective, do I gain anything by going with the second approach or does the first make more sense?
我强烈建议不要用垃圾填满您的 CPU 缓存。事实上,我避免使用任何会产生大量垃圾的结构。您可以构建一个系统,它端到端 为每个事件创建少于一个对象。我有一个伊甸园大小,它比我一天产生的垃圾量还大,所以没有 GC minor 或 full 需要担心。
Has anyone implemented this type of pattern before?
五年前,我用 Java 编写了一个可盈利的低延迟交易系统。当时它在 Java 中以 60 微秒为单位进行交易已经足够快了,但现在你可以做得更好。
如果你想要低延迟的市场数据处理系统,我就是这样做的。您可能会发现我在 JavaOne 上所做的这个演示也很有趣。
http://www.slideshare.net/PeterLawrey/writing-and-testing-high-frequency-trading-engines-in-java
编辑我添加了这个 parsing example
ByteBuffer wrap = ByteBuffer.allocate(1024);
ByteBufferBytes bufferBytes = new ByteBufferBytes(wrap);
byte[] bytes = "BAC,12.32,12.54,12.56,232443".getBytes();
int runs = 10000000;
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
bufferBytes.reset();
// read the next message.
bufferBytes.write(bytes);
bufferBytes.position(0);
// decode message
String word = bufferBytes.parseUTF(StopCharTesters.COMMA_STOP);
double low = bufferBytes.parseDouble();
double curr = bufferBytes.parseDouble();
double high = bufferBytes.parseDouble();
long sequence = bufferBytes.parseLong();
if (i == 0) {
assertEquals("BAC", word);
assertEquals(12.32, low, 0.0);
assertEquals(12.54, curr, 0.0);
assertEquals(12.56, high, 0.0);
assertEquals(232443, sequence);
}
}
long time = System.nanoTime() - start;
System.out.println("Average time was " + time / runs + " nano-seconds");
当设置 -verbose:gc -Xmx32m 时打印
Average time was 226 nano-seconds
注意:没有触发 GC。
关于java - 在线程池中重用 Runnable 有意义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19121856/