Python學習---同步條件event/隊列queue1223

寫在前面:html

在使用這些共享API的時候,咱們要注意如下幾點:安全

  在UNIX平臺上,當某個進程終結以後,該進程須要被其父進程調用wait,不然進程成爲殭屍進程(Zombie)。因此,有必要對每一個Process對象調用join()方法 (實際上等同於wait)。對於多線程來講,因爲只有一個進程,因此不存在此必要性。多線程

  multiprocessing提供了threading包中沒有的IPC(好比PipeQueue),效率上更高。應優先考慮PipeQueue,避免使用Lock/Event/Semaphore/Condition等同步方式 (由於它們佔據的不是用戶進程的資源)app

  多進程應該避免共享資源。在多線程中,咱們能夠比較容易地共享資源,好比使用全局變量或者傳遞參數。在多進程狀況下,因爲每一個進程有本身獨立的內存空間,以上方法並不合適。此時咱們能夠經過共享內存和Manager的方法來共享資源。但這樣作提升了程序的複雜度,並由於同步的須要而下降了程序的效率。dom

Process.PID中保存有PID,若是進程尚未start(),則PIDNone函數

  window系統下,須要注意的是要想啓動一個子進程,必須加上那句if __name__ == "main",進程相關的要寫在這句下面。spa

同步條件event

   條件同步和條件變量同步差很少意思,只是少了鎖功能,由於條件同步設計於不訪問共享資源的條件環境。操作系統

圍繞一個標誌位來進行判斷線程

event=threading.Event():條件環境對象,初始值 爲False;設計

event.isSet():返回event的狀態值;

event.wait():若是 event.isSet()==False將阻塞線程;

event.set(): 設置event的狀態值爲True,全部阻塞池的線程激活進入就緒狀態, 等待操做系統調度;

event.clear():恢復event的狀態值爲False。

案例一:

import threading,time
class Boss(threading.Thread):
    def run(self):
        print("BOSS:今晚你們都要加班到22:00。")
        event.isSet() or event.set()
        time.sleep(5)
        print("BOSS:<22:00>能夠下班了。")
        event.isSet() or event.set()
class Worker(threading.Thread):
    def run(self):
        event.wait()
        print("Worker:哎……命苦啊!")
        time.sleep(0.25)
        event.clear()
        event.wait()
        print("Worker:OhYeah!")
if __name__=="__main__":
    event=threading.Event()
    threads=[]
    for i in range(5):
        threads.append(Worker())
    threads.append(Boss())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

案例二:

import threading,time
import random
def light():
    if not event.isSet():
        event.set() #wait就不阻塞 #綠燈狀態
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if event.isSet():
                event.clear()
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            event.set() #打開綠燈
        time.sleep(1)
        count +=1
def car(n):
    while 1:
        time.sleep(random.randrange(10))
        if  event.isSet(): #綠燈
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()

多線程利器---隊列queue

隊列由於是可使2遍都開口,因此FIFO,棧是開頭封閉,只能從底部出,因此先進後出

Python Queue模塊有三種隊列及構造函數:

一、Python Queue模塊的FIFO隊列先進先出。   class queue.Queue(maxsize)

二、LIFO相似於堆,即先進後出。              class queue.LifoQueue(maxsize)

三、還有一種是優先級隊列級別越低越先出來。   class queue.PriorityQueue(maxsize)

注意:列表時線程不安全的,隊列是安全的,內部有一把鎖保證了我數據的安全

import queue
# 隊列長度可爲無限或者有限,默認是Queue(0),表示無限長
d = queue.Queue(2)  #可經過Queue的構造函數的可選參數maxsize來設定隊列長度,若是maxsize小於1就表示隊列長度無限。
d.put('hello', 0) # 第一個item爲必需的,爲插入項目的值;
                  # 第二個block爲可選參數,默認爲1。若是隊列當前爲空且block爲1,線程阻塞,直到空出一個數據單元
                  # 若是block爲0,put方法將引起Full異常。
d.put('world', 0)
# d.put('2017', 0) # 第三個,阻塞報異常
print(d.get())    # get()方法從隊頭刪除並返回一個項目。可選參數爲block,默認爲True。
                  # 若是隊列爲空且block爲True,get()就使調用線程暫停,直至有項目可用。
                  # 若是隊列爲空且block爲False,隊列將引起Empty異常。
print(d.get())

image

隊列的方法

此包中的經常使用方法(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() 函數向任務已經完成的隊列發送一個信號

實例一:

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()

image

FTP做業

更多參考

相關文章
相關標籤/搜索