Java 为什么消费者会减少生产者';s的表现
我目前正试图通过实现生产者-消费者模式来提高软件的性能。在我的特殊情况下,我有一个生产者,它按顺序创建行,还有多个消费者,它们为给定的一批行执行某些任务 我现在面临的问题是,当我衡量生产者-消费者模式的性能时,我可以看到生产者的运行时间大幅增加,我不明白为什么会出现这种情况 到目前为止,我主要分析了我的代码,并进行了微基准测试,但结果并没有让我发现实际问题Java 为什么消费者会减少生产者';s的表现,java,multithreading,performance,executorservice,producer-consumer,Java,Multithreading,Performance,Executorservice,Producer Consumer,我目前正试图通过实现生产者-消费者模式来提高软件的性能。在我的特殊情况下,我有一个生产者,它按顺序创建行,还有多个消费者,它们为给定的一批行执行某些任务 我现在面临的问题是,当我衡量生产者-消费者模式的性能时,我可以看到生产者的运行时间大幅增加,我不明白为什么会出现这种情况 到目前为止,我主要分析了我的代码,并进行了微基准测试,但结果并没有让我发现实际问题 public class ProdCons { static class Row { String[] _cols
public class ProdCons {
static class Row {
String[] _cols;
Row() {
_cols = Stream.generate(() -> "Row-Entry").limit(5).toArray(String[]::new);
}
}
static class Producer {
private static final int N_ITER = 8000000;
final ExecutorService _execService;
final int _batchSize;
final Function<Row[], Consumer> _f;
Producer(final int batchSize, final int nThreads, Function<Row[], Consumer> f) throws InterruptedException {
_execService = Executors.newFixedThreadPool(nThreads);
_batchSize = batchSize;
_f = f;
// init all threads to exclude their generaration time
startThreads();
}
private void startThreads() throws InterruptedException {
List<Callable<Void>> l = Stream.generate(() -> new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep(10);
return null;
}
}).limit(4).collect(Collectors.toList());
_execService.invokeAll(l);
}
long run() throws InterruptedException {
final long start = System.nanoTime();
int idx = 0;
Row[] batch = new Row[_batchSize];
for (int i = 0; i < N_ITER; i++) {
batch[idx++] = new Row();
if (idx == _batchSize) {
_execService.submit(_f.apply(batch));
batch = new Row[_batchSize];
idx = 0;
}
}
final long time = System.nanoTime() - start;
_execService.shutdownNow();
_execService.awaitTermination(100, TimeUnit.MILLISECONDS);
return time;
}
}
static abstract class Consumer implements Callable<String> {
final Row[] _rowBatch;
Consumer(final Row[] data) {
_rowBatch = data;
}
}
static class NoOpConsumer extends Consumer {
NoOpConsumer(Row[] data) {
super(data);
}
@Override
public String call() throws Exception {
return null;
}
}
static class SomeConsumer extends Consumer {
SomeConsumer(Row[] data) {
super(data);
}
@Override
public String call() throws Exception {
String res = null;
for (int i = 0; i < 1000; i++) {
res = "";
for (final Row r : _rowBatch) {
for (final String s : r._cols) {
res += s;
}
}
}
return res;
}
}
public static void main(String[] args) throws InterruptedException {
final int nRuns = 10;
long totTime = 0;
for (int i = 0; i < nRuns; i++) {
totTime += new Producer(100, 1, (data) -> new NoOpConsumer(data)).run();
}
System.out.println("Avg time with NoOpConsumer:\t" + (totTime / 1000000000d) / nRuns + "s");
totTime = 0;
for (int i = 0; i < nRuns; i++) {
totTime += new Producer(100, 1, (data) -> new SomeConsumer(data)).run();
}
System.out.println("Avg time with SomeConsumer:\t" + (totTime / 1000000000d) / nRuns + "s");
}
公共类产品{
静态类行{
字符串[]\u cols;
第()行{
_cols=Stream.generate(()->“Row Entry”).limit(5).toArray(字符串[]::new);
}
}
静态类生产者{
私有静态最终整数N_ITER=8000000;
最终执行服务(execService);;
最终int_批量大小;
最终函数f;
生产者(final int batchSize,final int nThreads,函数f)抛出InterruptedException{
_execService=Executors.newFixedThreadPool(nThreads);
_batchSize=batchSize;
_f=f;
//初始化所有线程以排除其生成时间
startThreads();
}
私有void startThreads()引发InterruptedException{
List l=Stream.generate(()->new Callable(){
@凌驾
public Void call()引发异常{
睡眠(10);
返回null;
}
}).limit(4.collect(Collectors.toList());
_execService.invokeAll(l);
}
long run()抛出InterruptedException{
最终长启动=System.nanoTime();
int-idx=0;
行[]批=新行[_batchSize];
对于(int i=0;i新NoOpConsumer(数据)).run();
}
System.out.println(“无消费的平均时间:\t”+(totTime/1000000000d)/nRuns+“s”);
totTime=0;
对于(int i=0;inewsomeconsumer(data)).run();
}
System.out.println(“与某些消费者的平均时间:\t”+(totTime/1000000000d)/nRuns+“s”);
}
实际上,由于使用者与生产者在不同的线程中运行,我希望生产者的运行时间不受使用者工作负载的影响
#1个螺纹,#100个批量
NoOpConsumer的平均时间:0.7507254368s
与某些消费者的平均时间:1.5334749871s
请注意,时间度量只度量生产时间,而不度量消费时间,不提交任何作业平均需要约0.6秒
更令人惊讶的是,当我将线程数从1增加到4时,我得到了以下结果(4核超线程)
#4个螺纹,#100个批量
NoOpConsumer的平均时间:0.7741189636s
与某些消费者的平均时间:2.5561667638s
我做错了什么?我遗漏了什么?目前我不得不相信运行时间的差异是由于上下文切换或与我的系统相关的任何事情造成的。线程之间并没有完全隔离 看起来您的
SomeConsumer
类分配了大量内存,这会产生垃圾收集工作,该工作在所有线程之间共享,包括您的生产者线程
它还访问大量内存,这可能会将生产者使用的内存从一级或二级缓存中挤出。访问真实内存比访问缓存需要更长的时间,因此这可能会使生产者也需要更长的时间
还要注意的是,我实际上没有验证您是否正确地度量了生产者时间,而且很容易出错。主要原因-这不是消费者/生产者模式。这只是一个幼稚的fork/join。事实上,我的解释是不正确的:我误读了代码,所以我将其删除。@Boristeider,您是对的。这不是消费者/生产者模式mer/Producer模式,我为这个误导性的标题感到抱歉!@JBNizet我认为你是对的-代码只是在一些线程之间分割了一堆任务。没有生产者-消费者;除非你合作