本文是學習《Python核心編程》的學習筆記,介紹了Python中的全局解釋器鎖和經常使用的兩個線程模塊:thread, threading,並對比他們的優缺點和給出簡單的列子。python
Python代碼的執行都是有Python虛擬機進行控制的。當初設計Python的時候,考慮在主循環中只能有一個控制線程在執行,就像單核CPU進行多線程編程同樣。
怎麼作到這樣控制的呢?就是這裏的GIL來控制的,這個鎖用來保證同時只有一個線程在運行。編程
執行方式:服務器
這幾個細節知識點:多線程
因此,針對Python虛擬機單線程(GIL)的設計緣由,只有線程在執行I/O密集型的應用,才能更好的發揮Python的併發性。併發
Python多個模塊能夠進行多線程編程,包括:thread,threading等。他們均可以用來建立和管理線程。
thread模塊提供了基本的線程和鎖定支持,而threading模塊提供了更高級別,功能更全面的線程管理。app
推薦使用更高級別的threading模塊,下面是一個簡單的對比:ide
特徵要素 | thread | threading |
---|---|---|
功能全面性 | 基本(偏底層) | 全面,高級 |
守護進程 | 不支持 | 支持 |
線程同步原語 | 僅1個(Lock) | 不少(Lock,Semaphore,Barrier...) |
守護進程通常是一個等待客戶端請求服務的服務器。若是沒有客戶端請求,守護進程通常是空閒的。通常把一個線程設置成守護進程,就表示這個線程是不重要的。因此進程退出時是不須要等待這個守護線程完成的。函數
可是原先的thread 模塊是不區分守護或者非守護進程的,也就是說當主線程退出的時候,全部子線程都將終止,而無論他們是否仍在工做。若是你不想這種狀況發生,那麼就能夠採用threading模塊。整個Python程序(通常爲主線程)將在全部非守護進程退出是纔會退出。oop
設置守護進程,在線程啓動以前設置:thread.daemon = True
學習
方式1:建立一個thread實例,傳遞它一個函數
import threading from time import sleep, ctime sleep_times = [4, 2] def loop(threadNo, sleep_time): print('Start loop', threadNo, 'at:', ctime()) sleep(sleep_time) #Sleep一段時間 print('loop', threadNo, 'done at:', ctime()) def main(): print('starting at:', ctime()) threads = [] threadIds = range(len(sleep_times)) for i in threadIds: thread = threading.Thread(target=loop, args=(i,sleep_times[i])) threads.append(thread) for t in threads: # 依次啓動線程 t.start() for t in threads: # 等待全部線程完成 t.join() #將等待線程結束 print('all Done at :', ctime()) if __name__ == '__main__': main()
方式2:派生Thread的子類,並建立子類的實例
import threading from time import sleep, ctime sleep_times = [4, 2] class MyThread(threading.Thread): def __init__(self, func, args, name=''): threading.Thread.__init__(self) self.func = func self.name = name self.args = args def run(self): self.func(*self.args) def loop(threadNo, sleep_time): print('Start loop', threadNo, 'at:', ctime()) sleep(sleep_time) # Sleep一段時間 print('loop', threadNo, 'done at:', ctime()) def main(): print('starting at:', ctime()) threads = [] # 用於存儲全部線程實例的列表 threadIds = range(len(sleep_times)) for i in threadIds: # 建立線程實例 thread = MyThread(loop, (i, sleep_times[i])) threads.append(thread) for t in threads: # 依次啓動線程 t.start() for t in threads: # 等待全部線程完成 t.join() # 將等待線程結束 print('all Done at :', ctime()) if __name__ == '__main__': main()
因爲本人使用的python3.6,這個thread已經變成_thread
import _thread from time import sleep, ctime sleep_times = [4, 2] def loop(threadNo, sleep_time, lock): print('Start loop', threadNo, 'at:', ctime()) sleep(sleep_time) #Sleep一段時間 print('loop', threadNo, 'done at:', ctime()) lock.release() #釋放鎖 def main(): print('starting at:', ctime()) locks = [] threadIds = range(len(sleep_times)) for i in threadIds: #經過調用_thread.allocate_lock得到鎖對象 lock = _thread.allocate_lock() #經過acquire()方法取得鎖 lock.acquire() locks.append(lock) for i in threadIds: # 依次啓動線程 _thread.start_new_thread(loop, (i, sleep_times[i], locks[i])) for i in threadIds: # 若是當前的鎖Lock沒有釋放的話,一直循環等待 while locks[i].locked(): pass print('all Done at :', ctime()) if __name__ == '__main__': main()