几个小时前,我问了一个关于Python多线程的问题。为了理解它是如何工作的,我做了一些实验,这是我的测试:
使用线程的Python脚本:
import threading
import Queue
import time
s = 0;
class ThreadClass(threading.Thread):
lck = threading.Lock()
def __init__(self, inQ, outQ):
threading.Thread.__init__(self)
self.inQ = inQ
self.outQ = outQ
def run(self):
while True:
global s
#print self.getName()+" is running..."
self.item = self.inQ.get()
#self.inQ.task_done()
ThreadClass.lck.acquire()
s += self.item
ThreadClass.lck.release()
#self.inQ.task_done()
self.outQ.put(self.item)
self.inQ.task_done()
inQ = Queue.Queue()
outQ = Queue.Queue()
i = 0
n = 1000000
print "putting items to input"
while i<n:
inQ.put(i)
i += 1
start_time = time.time()
print "starting threads..."
for i in xrange(10):
t = ThreadClass(inQ, outQ);
t.setDaemon(True)
t.start()
inQ.join()
end_time = time.time()
print "Elapsed time is: %s"%(end_time - start_time)
print s
以下内容与简单的while循环具有相同的功能:
import Queue
import time
inQ = Queue.Queue()
outQ = Queue.Queue()
i = 0
n = 1000000
sum = 0
print "putting items to input"
while i<n:
inQ.put(i)
i += 1
print "while loop starts..."
start_time = time.time()
while inQ.qsize() > 0:
item = inQ.get()
sum += item
outQ.put(item)
end_time = time.time()
print "Elapsed time is: %s"%(end_time - start_time)
print sum
如果在您的计算机上运行这些程序,您可以看到线程比简单的while循环慢得多。我对线程有点困惑,想知道线程代码有什么问题。如何优化它(在这种情况下),以及为什么它比while循环慢?
答案 0 :(得分:2)
线程总是很棘手,因为Python中的线程是特殊的。
要讨论优化,你必须专注于特殊情况,否则没有单一的答案。 我的计算机上的初始线程解决方案在37.11秒运行。如果使用局部变量对每个线程的元素求和,然后仅在最后锁定,则时间下降到32.62秒。
确定。无线程解决方案在7.47秒运行。大。但是如果你想在Python中总结大量数字,你只需使用内置函数和。因此,如果我们使用没有线程的List和内置的总和,则时间下降到0.09秒。太好了!
为什么?
Python中的线程受全局解释器锁(GIL)的约束。他们永远不会并行运行Python代码。它们是真正的线程,但在内部,它们只允许在将GIL发布到另一个线程之前运行X Python指令。对于非常简单的计算,创建线程,锁定和上下文切换的成本远远大于简单计算的成本。所以在这种情况下,开销是计算本身的5倍。当你不能使用异步I / O或者你有同时运行的阻塞函数时,Python中的线程很有意思。
但是,为什么内置的总和比Python无线程解决方案更快?内置的总和是用C实现的,Python循环很好地吸收了性能。因此,使用内置总和迭代列表的所有元素要快得多。
总是这样吗?不,这取决于你在做什么。如果您将这些数字写入n个不同的文件,则线程解决方案可能有机会,因为在I / O期间释放GIL。但即使这样,我们也需要检查I / O缓冲/磁盘同步时间是否不会改变游戏规则。这种细节使得最终答案非常困难。因此,如果您想要优化某些内容,您必须拥有优化所需的内容。要汇总Python中的数字列表,只需使用内置的总和。