与单线程相比,奇怪的c ++ / java多线程性能结果

时间:2016-04-05 00:24:19

标签: java c++ multithreading

自从2天以来我一直在努力了解c ++线程池性能与单个线程相比的情况,然后我决定在java上做同样的事情,这时我注意到c ++和java上的行为是相同的。基本上我的代码很简单。

enter code here

import os
import time

source = [r'D:\python35']

target_dir = r"D:\Backup to harddisk 2016"

target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip'

if not os.path.exists(target_dir):
    os.mkdir(target_dir)

zip_command = "zip -r {0} {1}".format(target, ' '.join(source))
print('zip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
    print('Successful backup to', target)
else:
    print('Backup FAILED')

现在使用不同的池号表示相同的代码,例如100个线程,总体经过的时间将会改变。

one thread:
in time 36.91493612774451 lookups: 1002000

100 threads: in time 141.47934530938124 lookups: 1002000

问题是,代码是一样的,为什么整体经过的时间与这里的确切时间不同...

1 个答案:

答案 0 :(得分:0)

这里有几个显而易见的可能性。

一个是System.nanoTime可以在内部进行序列化,因此即使每个线程分别进行调用,它也可以在内部按顺序执行这些调用(例如,在它们进入时排队调用)。当nanoTime直接访问硬件时钟时尤其如此,例如在Windows上(使用Windows“QueryPerformanceCounter”)。

基本上顺序执行的另一个点是原子变量。即使你使用无锁原子,基本的事实是每个都必须执行读/修改/写作原子序列。使用锁定变量,通过锁定,读取,修改,写入和解锁来完成。使用无锁,您可以消除这样做的一些开销,但是您仍然坚持只有一个线程可以在给定时间成功读取,修改和写入特定内存位置的事实。

在这种情况下,每个线程执行的唯一“工作”是微不足道的,结果从未使用过,因此优化器可以(并且可能会)完全消除它。所以你真正测量的是读取时钟和增加变量的时间。

为了获得至少一些速度,你可以(举个例子)给线程线程自己的lookupstotalTime变量。然后,当所有线程完成后,您可以将各个线程的值相加,以获得每个线程的总计。

防止序列的序列化有点困难(说得客气一点)。至少在明显的设计中,每次调用nanoTime都会直接访问硬件寄存器,而硬件寄存器(至少在大多数典型硬件中)只能顺序发生。它可以在硬件级别进行修复(提供一个高频定时器寄存器,可以直接读取每个内核,保证在内核之间同步)。这是一项有点不重要的任务,而且(更重要的是)大多数现有硬件都没有包含这样的东西。

除此之外,在每个线程中执行一些有意义的工作,因此当您在多个线程中执行时,您有某些可以实际使用多个CPU /内核的资源来更快地运行。< / p>