我有以下任务,我想通过多线程(python3)更快地完成。
import threading, time
q = []
def fill_list():
global q
while True:
q.append(1)
if len(q) >= 1000000000:
return
第一个主要不使用多线程:
t1 = time.clock()
fill_list()
tend = time.clock() - t1
print(tend)
结果是145秒的运行时间。
第二个调用两个线程:
t1 = time.clock()
thread1 = threading.Thread(target=fill_list, args=())
thread2 = threading.Thread(target=fill_list, args=())
thread1.start()
thread2.start()
thread1.join()
thread2.join()
tend = time.clock() - t1
print(tend)
这需要152秒才能完成。
最后,我添加了第三个帖子。
t1 = time.clock()
thread1 = threading.Thread(target=fill_list, args=())
thread2 = threading.Thread(target=fill_list, args=())
thread3 = threading.Thread(target=fill_list, args=())
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
tend = time.clock() - t1
print(tend)
这需要233秒才能完成。
显然,我添加的线程越多,进程所需的时间越长,但我不确定原因。这是对多线程的一个基本误解,还是我的代码中有一个错误,就是多次重复执行任务而不是为同一个任务做出贡献?
答案 0 :(得分:5)
答案1和2。
首先,您的任务是受CPU限制的,并且在Python进程中,任何给定时间只有一个线程可能正在运行CPU绑定的Python代码(这是由于Global Interpreter Lock:https://wiki.python.org/moin/GlobalInterpreterLock) 。由于切换线程需要花费相当多的CPU(并且你拥有的线程越多,你就越需要支付这笔费用),你的程序不会加速:它会变慢。
其次,无论您使用何种语言,您都要从多个线程修改一个对象(列表)。但为了保证这不会破坏对象,必须同步访问。换句话说,只有一个线程可能在任何给定时间修改它。 Python自动完成(部分归功于前面提到的GIL),但在另一种低级语言(如C ++)中,你必须使用锁定或冒着内存损坏的风险。
跨线程并行化任务的最佳方法是确保线程尽可能隔离。如果他们访问共享对象,那些应该是只读,并且跨线程写入应该尽可能不经常发生,通过线程感知数据结构,如消息队列。
(这就是为什么像Erlang和Clojure这样的高性能并行系统如此高度重视不可变数据结构和消息传递)