与单线程相比,c++/java的多线程性能结果参差不齐
Odd c++/java multi threading performance results compared to single thread
从2天起,我就一直在努力理解c++线程池性能与单个线程相比发生了什么,然后我决定在java上也这样做,这时我注意到c++和java上的行为是相同的。。基本上,我的代码很简单。
package com.examples.threading
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
public class ThreadPool {
final static AtomicLong lookups = new AtomicLong(0);
final static AtomicLong totalTime = new AtomicLong(0);
public static class Task implements Runnable
{
int start = 0;
Task(int s) {
start = s;
}
@Override
public void run()
{
for (int j = start ; j < start + 3000; j++ ) {
long st = System.nanoTime();
boolean a = false;
long et = System.nanoTime();
totalTime.getAndAdd((et - st));
lookups.getAndAdd(1l);
}
}
}
public static void main(String[] args)
{
// change threads from 1 -> 100 then you will get different numbers
ExecutorService executor = Executors.newFixedThreadPool(1);
for (int i = 0; i <= 1000000; i++)
{
if (i % 3000 == 0) {
Task task = new Task(i);
executor.execute(task);
System.out.println("in time " + (totalTime.doubleValue()/lookups.doubleValue()) + " lookups: " + lookups.toString());
}
}
executor.shutdown();
while (!executor.isTerminated()) {
;
}
System.out.println("in time " + (totalTime.doubleValue()/lookups.doubleValue()) + " lookups: " + lookups.toString());
}
}
现在,当您使用不同的池号(比如说100个线程)运行相同的代码时,总运行时间将发生变化
一个线程:及时查找36.9149361274451:1002000
100个螺纹:及时查找141.47934530938124:1002000
问题是,代码是一样的,为什么总的运行时间不同,这里到底发生了什么。。
这里有几个明显的可能性。
一种是System.nanoTime
可以在内部串行化,因此即使每个线程单独进行调用,它也可以在内部按顺序执行这些调用(例如,在调用到来时对其进行排队)。当nanoTime直接访问硬件时钟时,这种情况尤其可能发生,例如在Windows上(它使用Windows的QueryPerformanceCounter
)。
另一个基本上按顺序执行的点是原子变量。尽管您使用的是无锁原子,但基本事实是,每个原子都必须作为原子序列执行读/修改/写。对于锁定的变量,这是通过锁定、读取、修改、写入和解锁来完成的。有了无锁,您可以消除这样做的一些开销,但您仍然面临这样一个事实,即在给定的时间只有一个线程可以成功地读取、修改和写入特定的内存位置。
在这种情况下,每个线程所做的唯一"工作"是琐碎的,和永远不会使用结果,因此优化器可以(可能也会)完全消除它。所以你真正测量的是读取时钟和增加变量的时间。
为了至少恢复一些速度,您可以(例如)给线程线程自己的lookups
和totalTime
变量。然后,当所有线程完成时,您可以将各个线程的值加在一起,以获得每个线程的总值。
防止时序的序列化稍微困难一些(委婉地说)。至少在显而易见的设计中,对nanoTime
的每次调用都直接访问一个硬件寄存器,这(至少对于大多数典型的硬件)只能顺序发生。它可以在硬件级别进行修复(提供一个高频定时器寄存器,每个内核可以直接读取,保证在内核之间同步)。这是一项不平凡的任务,(更重要的是)大多数当前的硬件都不包括这样的东西。
除此之外,在每个线程中做一些有意义的工作,这样当你在多个线程中执行时,你就有了东西,它实际上可以使用多个CPU/内核的资源来更快地运行。
- 在main()之外初始化std::vector会导致性能下降(多线程)
- Linux VM(重型多线程应用程序)的性能改进
- 使用较新版本的 g++ 导致多线程性能下降?
- 在多线程环境中使用 libcurl 会导致与 DNS 查找相关的性能非常慢
- C++多线程性能比单线程代码慢
- 提升 asio io_service多线程性能不佳
- 多线程功能性能比单线螺纹差
- 为什么c++中的多线程会降低性能
- 内存分配对多线程性能的影响
- C 11多线程在神经网络中的性能非常缓慢
- 2个数组/图像相乘的多线程性能-英特尔IPP
- 与单线程相比,c++/java的多线程性能结果参差不齐
- 可以通过减少多线程中系统调用(互斥/信号量)的开销来真正提高性能::atomic
- 为什么具有多线程的for循环的性能不如单线程
- C++独立数据的多线程性能
- PC多线程性能和稳定性问题的简单基准测试.如何使每个线程在单独的核心上运行
- 多线程性能问题
- 多线程性能
- 多线程性能在执行几次操作后下降
- QtConcurrent与多线程QThread的多线程性能