我首先在生产代码中观察到了这个问题,然后做了一个原型:
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个线程,我预计使用heavyfunc()的2个作业需要2.07秒。 (我的CPU是i7 =>有足够的内核)。
这是CPU监视器的截图,它也提供了没有真正多线程的想法:
我思考的错误在哪里?如何创建不干扰的n个线程?
答案 0 :(得分:4)
CPython不会同时在多个核心上执行字节码。多线程cpu绑定代码毫无意义。全局解释器锁(GIL)用于保护进程中的所有引用计数,因此一次只有一个线程可以使用Python对象。
您看到性能更差,因为您一次只有一个线程正在工作,但现在您也在更改线程上下文。