2

我首先在生产代码中观察到这个问题,然后制作了一个原型:

import threading, Queue, time, sys

def heavyfunc():
    ''' The idea is just to load CPU '''
    sm = 0
    for i in range(5000):
        for j in range(5000):
            if i + j % 2 == 0:
                sm += i - j
    print "sm = %d" % sm

def worker(queue):
    ''' worker thread '''
    while True:
        elem = queue.get()
        if elem == None: break
        heavyfunc()           # whatever the elem is


starttime = time.time()  

q = Queue.Queue()             # queue with tasks

number_of_threads = 1
# create & start number_of_threads working threads
threads = [threading.Thread(target=worker, args=[q]) for thread_idx in range(number_of_threads)]
for t in threads: t.start()

# add 2 working items: they are estimated to be computed in parallel
for x in range(2):
    q.put(1)

for t in threads: q.put(None) # Add 2 'None' => each worker will exit when gets them
for t in threads: t.join()    # Wait for every worker

#heavyfunc()

elapsed = time.time() - starttime

print >> sys.stderr, elapsed

Heavyfunc() 的思想只是加载 CPU,没有任何同步和依赖。

使用 1 个线程时,平均需要 4.14 秒 使用 2 个线程时,平均需要 6.40 秒 不使用任何线程时,计算 heavyfunc() 平均需要 2.07 秒(多次测量,正好是 4.14 / 2,如如果有 1 个线程和 2 个任务)。

如果有 2 个线程,我预计有 2 个使用 heavyfunc() 的作业需要 2.07 秒。(我的 CPU 是 i7 => 有足够的核心)。

这是 CPU 监视器的屏幕截图,也表明没有真正的多线程:

CPU 负载图

我的思维错误在哪里?如何创建不干扰的 n 个线程?

4

1 回答 1

5

CPython 不会一次在多个内核上执行字节码。多线程 cpu-bound 代码毫无意义。全局解释器锁 (GIL) 用于保护进程中的所有引用计数,因此一次只有一个线程可以使用 Python 对象。

您看到的性能更差,因为您一次仍然只有一个线程在工作,但现在您也在更改线程上下文。

于 2012-06-28T15:56:10.637 回答