我有一个java程序,其中包含一个发送消息的生产者和处理它们的消费者。下面是我的代码的简化版本,有两个测试来重现问题。
类MyActor 是一个消费者线程。它只是循环读取来自并发队列的消息并对它们进行计数。
TestestMessagesToThread 是一个通过将200M消息发布到MyActor队列来同步发送200M消息的测试。它在我的机器上以每秒6M的速率工作。
testMessagesToThreadAsync 是一个以异步方式发送200M消息的测试。为了做到这一点,它创建了带有1个线程的ExecutorService,并且消息从该线程异步发布到MyActor队列。此测试每秒几乎不会达到100K消息,并且随着时间的推移会降低性能。
如何在使用ExecutorService时以 TestestMessagesToThread 的速率运行 TestestMessagesToThread ,或者至少了解为什么它不可能。
public class TestSingleThread {
public static int WARM_UP_NUMBER = 1000000;
public static int MSG_NUMBER = 200000000;
private static ExecutorService _executor = Executors.newSingleThreadExecutor();
public static class MyActor extends Thread {
public Queue<Integer> _messageQueue = new ConcurrentLinkedQueue();
private int _counter = 0;
private long _time = System.currentTimeMillis();;
public void run() {
while (true){
Integer msg = _messageQueue.poll();
if (msg == null)
continue;
_counter++;
if (_counter == TestSingleThread.WARM_UP_NUMBER) {
System.out.println("Warm-up completed. Staring Measurement. Warm up time: " + (System.currentTimeMillis() - _time));
_time = System.currentTimeMillis();
}
if (_counter == TestSingleThread.MSG_NUMBER + TestSingleThread.WARM_UP_NUMBER) {
long endTime = System.currentTimeMillis();
long ms = endTime - _time;
System.out.println("Time for " + TestSingleActor.MSG_NUMBER+ " messages. " + ms);
System.out.println("msg/sec - " + (int) ((double) TestSingleActor.MSG_NUMBER / ms) * 1000);
_time = endTime;
break;
}
}
System.out.println("Thread Run ends");
return;
}
public void tell(Integer msg) {
_messageQueue.add(msg);
}
public void tellAsync(Integer msg) {
_executor.submit(() -> {
_messageQueue.add(msg);
});
}
}
@Test
public void testMessagesToThread() throws InterruptedException {
MyActor actor = new MyActor();
actor.start();
IntStream.range(0, TestSingleActor.MSG_NUMBER + TestSingleActor.WARM_UP_NUMBER).sequential().forEach(record -> actor.tell(1));
System.out.println("Complete Sending");
actor.join();
return;
}
@Test
public void testMessagesToThreadAsync() throws InterruptedException {
MyActor actor = new MyActor();
actor.start();
IntStream.range(0, TestSingleActor.MSG_NUMBER + TestSingleActor.WARM_UP_NUMBER).sequential().forEach(record -> actor.tellAsync(5));
System.out.println("Complete Sending");
actor.join();
}
}