多線程 什麼是線程? - 能獨立運行的基本單位——線程(Threads)。 - 線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。 - 一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。 - 就好比生產的工廠,一個車 ...
多線程
什麼是線程?
- 能獨立運行的基本單位——線程(Threads)。
- 線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。
- 一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。
- 就好比生產的工廠,一個車間的工作過程是一個進程,車間中的一條條流水線工作的過程是不同的線程。
下麵的圖片就是線程與進程之間的關係
註意:進程是資源分配的最小單位,線程是CPU調度的最小單位.
每一個進程中至少有一個線程。
線程與進程的區別可以歸納為以下4點:
1)地址空間和其它資源(如打開文件):進程間的地址空間相互獨立,同一進程的各線程間共用進程的地址空間。某進程內的線程在其它進程不可見
2)通信:進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變數)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性
3)調度和切換:線程上下文切換比進程上下文切換要快得多
4)在多線程操作系統中,進程不是一個可執行的實體
創建多線程簡例
import time import threading def foo(n): print('線程%s'%n) time.sleep(3) print('線程%s結束' % n) def bar(n): print('線程%s' % n) time.sleep(2) print('線程%s結束' % n) begin = time.time() print('------------主線程------------') # 創建線程對象 t1 = threading.Thread(target = foo,args = (1,)) t2 = threading.Thread(target = bar,args = (2,)) # 通過 os 調度來搶占 cpu資源 t1.start() t2.start() # 線程不結束就不會繼續向下進行 t1.join() t2.join() end = time.time() print(end-begin)
join()方法
- join()方法會使線程在join處進行阻塞,倘若線程沒完成就不會繼續向下運行
import time import threading from time import ctime,sleep def music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(4) print("----------end listening %s----------"%ctime()) def moive(func): for i in range(2): print ("Begin watching at the %s! %s" %(func,ctime())) sleep(5) print('----------end watching %s----------'%ctime()) threads = [] t1 = threading.Thread(target=music,args=('晴天',)) threads.append(t1) t2 = threading.Thread(target=moive,args=('肖申克的救贖',)) threads.append(t2) if __name__ == '__main__': start = time.time() for t in threads: t.start() #t.join() # t 先取的值為 t1 ,t1不結束就不會繼續向下走,此時相當於串列 #t1.join() # 與 t.join() 效果一致 t.join() # 在python中不會報錯,此時取值為 t2 #t2.join() # 在 t2 運行完成後,才會完成後續代碼 print ("all over %s" %ctime()) end = time.time() print(end - start)
守護線程 Daemon
- 守護線程setDaemon(True),必須在start() 方法調用之前設置,否則將會報錯
- 如果不設置為守護線程程式會被無限掛起。這個方法基本和join是相反的。
- 主線程一旦結束,子線程也同時結束
- 當主線程完成時不需要某個子線程完全運行完就要退出程式,那麼就可以將這個子線程設置為守護線程,
import threading import time class MyThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): # 定義每個線程要運行的函數 print("running on number:%s" % self.num) time.sleep(10) if __name__ == '__main__': begin = time.time() t1 = MyThread(1) t2 = MyThread(2) threads = [t1, t2] for t in threads: t.setDaemon(True) t.start() print('進程結束!') end = time.time() print(end-begin)
隊列 queue
- queue類的方法
創建一個“隊列”對象 import Queue q = Queue.Queue(maxsize = 10) Queue.Queue類即是一個隊列的同步實現。隊列長度可為無限或者有限。可通過Queue的構造函數的可選參數maxsize來設定隊列長度。如果maxsize小於1就表示隊列長度無限。 將一個值放入隊列中 q.put(10) 調用隊列對象的put()方法在隊尾插入一個項目。put()有兩個參數,第一個item為必需的,為插入項目的值;第二個block為可選參數,預設為 1。如果隊列當前為空且block為1,put()方法就使調用線程暫停,直到空出一個數據單元。如果block為0,put方法將引發Full異常。 將一個值從隊列中取出 q.get() 調用隊列對象的get()方法從隊頭刪除並返回一個項目。可選參數為block,預設為True。如果隊列為空且block為True,get()就使調用線程暫停,直至有項目可用。如果隊列為空且block為False,隊列將引發Empty異常。 Python Queue模塊有三種隊列及構造函數: 1、Python Queue模塊的FIFO隊列先進先出。 class queue.Queue(maxsize) 2、LIFO類似於堆,即先進後出。 class queue.LifoQueue(maxsize) 3、還有一種是優先順序隊列級別越低越先出來。 class queue.PriorityQueue(maxsize) 此包中的常用方法(q = Queue.Queue()): q.qsize() 返回隊列的大小 q.empty() 如果隊列為空,返回True,反之False q.full() 如果隊列滿了,返回True,反之False q.full 與 maxsize 大小對應 q.get([block[, timeout]]) 獲取隊列,timeout等待時間 q.get_nowait() 相當q.get(False) 非阻塞 q.put(item) 寫入隊列,timeout等待時間 q.put_nowait(item) 相當q.put(item, False) q.task_done() 在完成一項工作之後,q.task_done() 函數向任務已經完成的隊列發送一個信號 q.join() 實際上意味著等到隊列為空,再執行別的操作
隊列的簡例
import threading,queue from time import sleep from random import randint class Production(threading.Thread): def run(self): while True: r = randint(0,100) q.put(r) print("生產出來%s號包子"%r) sleep(1) class Proces(threading.Thread): def run(self): while True: re = q.get() print("吃掉%s號包子"%re) if __name__=="__main__": q = queue.Queue(10) threads = [Production(),Production(),Production(),Proces()] for t in threads: t.start()