2015-06-19 147 views
2

我有以下任务,我想通过多线程(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秒才能完成。

很明显,我添加的线程越多,处理所需的时间越长,但我不知道为什么。这是对多线程的基本误解,还是我的代码中存在一个错误,它只是多次重复执行任务,而不是对同一任务做出贡献?

+2

你已经发现[GIL的(HTTPS://wiki.python .ORG /莫因/ GlobalInterpreterLock)。 – dano

回答

5

答案1和2

首先,你的任务是CPU绑定,并在Python进程只有一个线程可以在任何给定的时间(运行CPU密集型的Python代码,这是由于全球口译员锁:https://wiki.python.org/moin/GlobalInterpreterLock)。由于切换线程需要花费相当多的CPU资源(并且线程数越多,需要付出的代价越多),程序不会加速:速度变慢。其次,无论您使用何种语言,您都需要修改多个线程中的一个对象(列表)。但为了保证这不会破坏对象,访问必须同步。换句话说,只有一个线程可能在任何给定时间修改它。 Python会自动执行它(部分归功于前面提到的GIL),但是在另一个低级语言(如C++)中,您必须使用锁定或冒内存损坏。

跨线程并行化任务的最佳方式是确保线程尽可能地孤立。如果他们访问共享对象,那么应该是只读,并且跨线程写入应该尽可能少地通过线程感知数据结构(如消息队列)发生。

(这就是为什么像Erlang和Clojure的最高效的并行系统将如此高的重视不可改变的数据结构和消息传递)