我有很多任务可以并行完成。这个单线程和多线程我都试过了。代码如下:
private MyTaskResult doTasks( ... ) {
try ( var scope = new StructuredTaskScope.ShutdownOnFailure() ) {
var negTask =
MyTask.create(
...
);
var posTask =
MyTask.create(
...
);
var negTaskFuture = (
CoreConfig.useMultipleThreads() ?
scope.fork( negTask::task ) :
new ImmediateFuture<>( negTask.task() )
);
var posTaskFuture = (
CoreConfig.useMultipleThreads() ?
scope.fork( posTask::task) :
new ImmediateFuture<>( posTask.task() )
);
scope.join();
scope.throwIfFailed();
return new MyTaskResult(
negTaskFuture.resultNow(),
posTaskFuture.resultNow()
);
}
catch ( InterruptedException | ExecutionException ex ) {
throw new Error( ex );
}
}
对于两个任务中的每一个,单线程执行的时间通常约为 3 毫秒,加上一些开销,总共 7 毫秒。多线程执行的时间为每个任务 9 毫秒,总计 11 毫秒的一些开销。时间上有些不一致,一项任务有时只需 3 毫秒,而另一项任务通常需要 9 毫秒。任务对象是用自己的数据项(严格不可变的)创建的,并且不与其他数据源交互。任务进行一些计算并相应地创建数据结构。
我的期望是单线程执行时间 7ms elapsed 会加速到 4/5ms elapsed。这个例子并不重要,但它不是我做这项工作的唯一地方。我从其他代码块中得到了类似的结果。我没有展示这些示例,因为它们引用了一个中央数据存储库,并且所有生成的线程都必须争夺读写访问权限(我使用了 ReentrantReadWriteLock),因此在这种情况下可能会发生阻塞。即便如此,结果与我上面介绍的情况类似,多线程需要 2-3 倍的时间,尽管线程数量更多。注意 synchronized 没有使用。
我一定是在做蠢事。请帮忙?
环境是 IntelliJ,最新版本。
我最终确实解决了这个问题。这花了一些时间,因为该程序比较复杂,需要进行大量重写和试验。在某些情况下,争用访问计算中心的大型共享对象是原因。争用似乎接近 100%,对该对象的访问似乎是限制因素。
消除争用后会发现一组 [较少] 争用的日志和计时器,它们也会降低性能。消除对这些对象的争用导致预期的性能改进。
我从中吸取的教训是,在具有大量共享资源的情况下,通过并发实现性能改进并不简单。
在我的例子中,部分解决方案需要完全重写以消除所有争用并存储在每个线程中运行的计算结果,以便稍后合并到共享的中央资源中。这种合并有额外的成本,因为线程并行运行类似的计算,导致必须处理一些数据重复。