Python 多線程 -thread threading Queue- 簡單學習html
在實際工做過程當中,會出現須要併發的作一些事情,例如一臺機器測到幾千臺機器的網絡連通性,若是你單線程一臺一臺測的話,會花費不少的事情,不具備實時性,更不能在變化的時候馬上感知當時網絡的情況,這時多線程就是一個很好地選擇。python已經給咱們封裝好了多線程庫thread和threading。python
thread:比較底層的模塊
threading:Higher-level threading interfacegit
ps:建議使用threading模塊
- 高級別的threading模塊更爲先進,對線程的支持更爲完善
- 低級別的thread模塊同步原語不多
- thread模塊對線程何時結束徹底沒有控制,當主線程結束時,全部線程都會強制結束github
模塊函數web
start_new_thread(function, args,kwargs=None): 產生新的線程,args是function的參數,沒有時寫(),kwargs用來調用這個函數
allocate_lock(): 分配鎖,LockType類型
exit(): 讓線程退出canvas
LockType的操做ruby
acquire(wait=None):嘗試獲取鎖
locked(): 獲取了鎖返回True,沒有返回False
release():釋放鎖markdown
Demo1網絡
$ cat t1.py import thread from time import sleep def a(): print "a start" sleep(2) print "a end" def b(): print "b start" sleep(2) print "b end" def main(): thread.start_new_thread(a,()) thread.start_new_thread(b,()) print "all done" if __name__ == "__main__": main() $ python t1.py all done b start a start
最終會發現,每一次運行出來的結果都有可能不一樣,可是絕對不會出現「a end」和「b end」。這是爲何呢,這裏沒有寫讓主線程停下來等全部子線程結束後再繼續運行的代碼,因此main線程在執行完print "all done"
就關閉了a和b兩個線程。怎麼辦呢,能夠在這裏加一個sleep等待子進程執行完畢後再退出。多線程
Demo2: thread -- 多線程的演示 by sleep
$ cat t2.py import thread from time import sleep def a(): print "a start" sleep(2) print "a end" def b(): print "b start" sleep(2) print "b end" def main(): thread.start_new_thread(a,()) thread.start_new_thread(b,()) sleep (4) ----防止主進程過早退出,加sleep等待子進程執行完畢後再推出 print "all done" if __name__ == "__main__": main() $ python t1.py b start a start a end b end all done
可是假設咱們不知道子進程執行的時間怎麼辦,這就是鎖的用武之地了。由於使用鎖要比使用sleep()函數更爲合理。以下所示:
Demo3: thread -- 多線程演示 by lock
實現方式爲: 主線程初始化兩個鎖,分別傳給兩個函數,兩個函數在執行完本身的代碼後釋放鎖,主線程一直在輪詢這個鎖有沒有釋放,若是釋放了就退出。
def a(lock, nsec): print "a starting at :", ctime() sleep(nsec) lock.release() -- 執行完以後釋放鎖 print "a end", ctime() def b(lock, nsec): print "b starting at :", ctime() sleep(nsec) lock.release() -- 執行完以後釋放鎖 print "b end", ctime() def main(): print "Demo Starting at:", ctime() locks = [] # Initialize lock -- 主線程先獲取兩個鎖,佔爲己有 for i in range(2): lock = thread.allocate_lock() lock.acquire() locks.append(lock) # 每一個進程分配一個鎖 thread.start_new_thread(a, (locks[0],2)) thread.start_new_thread(b, (locks[1],4)) for i in range(2): #一直在輪詢,看鎖有沒有釋放 while locks[i].locked(): pass print "all done at:", ctime()
最後的結果爲:
$ python thread_demo.py Demo Starting at: Fri Aug 29 22:03:01 2014 a starting at : Fri Aug 29 22:03:01 2014 b starting at : Fri Aug 29 22:03:01 2014 a end Fri Aug 29 22:03:03 2014 b end Fri Aug 29 22:03:05 2014 all done at: Fri Aug 29 22:03:05 2014
不難發現,thread庫的同步機制比較難用,一切都須要主進程來處理。而且沒有守護進程,主進程一退,整個世界都會變得很清靜。而threading庫給咱們提供了守護進程。下面就來看看threading的簡單用法。
threading提供了Thread類,還提供了不少很是好用的同步機制。感受重點了解Thread類就能夠,多線程,也就是經過Thread類的多個實例。 類的主要方法有:
start():開始線程的執行。thread庫裏裏面,是沒有辦法控制線程的開始的
join(timeout=None): 等待線程結束,有點相似Demo3中的輪詢
run():定義線程的功能
感受上面是比較重要的,立馬就會用到的。還有一些其餘的:
getName():獲取線程名
setName(name):設置線程名
isAlive(): 返回bool 表示線程是否在運行中
activeCount():返回運行中的線程數
currentThread():返回當前線程對象
enumerate():返回當前活動線程的列表
isDaemon(): 返回線程的Daemon標誌
setDaemon(daemonic): 設置線程的Daemon標誌,通常在start()函數前調用
settrace(func):爲全部線程設置跟蹤函數
setprofile(func): 爲全部線程設置profile函數
Demo4 -- threading演示
def loop(i, nsec): print "thread %d starting at : %s" %(i, ctime()) sleep(nsec) print "thread %d end at : %s" %(i, ctime()) def main(): threads = [] loops = [2, 4] # 實例化進程 for i in range(len(loops)): t = threading.Thread(target = loop, args = (i, loops[i])) threads.append(t) for i in range(len(loops)): threads[i].start() for i in range(len(loops)): threads[i].join() print "all done"
最後的結果爲:
thread 0 starting at : Sun Aug 31 13:31:28 2014 thread 1 starting at : Sun Aug 31 13:31:28 2014 thread 0 end at : Sun Aug 31 13:31:30 2014 thread 1 end at : Sun Aug 31 13:31:32 2014 all done
可見threading能夠方便的控制線程的開始,以及等待每一個線程的結束,而且也不用設置鎖,釋放鎖,這些都被threading庫封裝了,相比於thread要更高級一些。在實際的運維工程中,可能會須要多個線程執行相同的任務,這時須要一個任務池。每一個線程取任務池中取任務,執行,再取任務,再執行,一直到任務池爲空,退出線程。這裏就會用到下面要介紹的Queue庫。
Queue模塊能夠用來實現多線程間通信,讓各個線程共享數據,生產者把貨物放到Queue中,供消費者(線程)去使用。在python3中,Queue模塊被命名爲queue。 Queue的對象有:
Queue.Queue(maxsize=0): 建立大小爲maxsize的FIFO(First In First Out)-Queue對象,若是maxsize不設置,這個隊列將是無限的。
Queue.LifoQueue(maxsize=0): 建立先入後出的對象,即棧, 在python2.6中加入 Queue.PriorityQueue(maxsize=0):有優先級的隊列,在python2.6中加入
Queue對象的方法有:
qsize():返回隊列的大小
empty():返回隊列時候爲空
full():返回隊列是否滿
put(item,block=0):向Queue對象中放數據,block不爲0時,會一直等到隊列中有控件爲止
get(block=0):,同上,block不爲0時,會一直等到隊列中有數據爲止
Demo5 -- Queue的使用演示:
場景: Queue裏面放着一些整數,須要將整數取出,而且睡眠整數大小的時間,下面的demo中,是放了10個1,若是單線程的話須要10s
def work(q): while True: if q.empty(): return else: t = q.get() time.sleep(t) def main(): q = Queue.Queue() # 初始化一個Queue對象 for i in range(10): # 向Queue生產任務 q.put(1) work(q) if __name__ == "__main__": main()
最後的結果爲:
time python threading_demo2.py real 0m10.085s user 0m0.060s sys 0m0.004s
單線程的話須要花費10s。
下面來經過多線程來處理Queue裏面的任務:
def work(q): while True: if q.empty(): return else: t = q.get() time.sleep(t) def main(): q = Queue.Queue() for i in range(10): q.put(1) thread_num = 10 threads = [] for i in range(thread_num): t = threading.Thread(target = work, args = (q,)) # args須要輸出的是一個元組,若是隻有一個參數,後面加,表示元組,不然會報錯 threads.append(t) for i in range(thread_num): threads[i].start() for i in range(thread_num): threads[i].join()
看看這下的結果爲:
real 0m1.046s user 0m0.024s sys 0m0.020s
所以對python多線程,主要學會使用threading和Queue,應該就能夠足以應付運維中的一些問題。