【python】-- 信號量(Semaphore)、event(紅綠燈例子)


信號量(Semaphore)

之前講的線程鎖(互斥鎖) 同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據 ,比如廁所有3個坑,那最多只允許3個人上廁所,后面的人只能等里面有人出來了才能再進去。

1、信號量

  1. 是一個變量,控制着對公共資源或者臨界區的訪問。信號量維護着一個計數器,指定可同時訪問資源或者進入臨界區的線程數。 
  2. 每次有一個線程獲得信號量時,計數器-1。若計數器為0,其他線程就停止訪問信號量,直到另一個線程釋放信號量

說白了就是在同一時間,可以只允許設定的數量的線程去執行

import threading
import time


def run(n):
    semaphore.acquire()   # 加信號量鎖
    time.sleep(5)
    print("run the thread: %s\n" % n)
    semaphore.release()   # 釋放信號量鎖


if __name__ == '__main__':

    semaphore = threading.BoundedSemaphore(5)  # 最多允許5個線程同時運行(Bounded:綁定,Semaphore:信號量)
    for i in range(20):
        t = threading.Thread(target=run, args=(i,))
        t.start()

while threading.active_count() != 1:
    pass
else:
    print('----all threads done---')

上面程序的執行,會讓人感覺是:分了4組,前5個同時完成,然后又5個同時進去。但是實際的效果是:這5個里面如果有3個完成,就會立刻再放3個進去。不會等5個都完成,每出來1個就放進去1個,出來幾個放進去幾個

2、使用場景和總結

  1. 連接池,線程池,MySQL的有連接池,同一時間有多少個並發,就能連多少個連接。
  2. 我們為了保證我的socket_server,因為python不會默認現在你啟動多少個線程,但是你啟動的線程越多,就會把系統拉的越慢,就會把程序拉的越慢。這里就可以搞一個我同一時間放100線程個進來,就是用semaphore
  3. python3.x 雖然不加鎖也是正確的,但是最好還是把鎖加上

 

 

event(紅綠燈例子)

日常生活中經常遇到紅綠燈,我們就很好理解紅綠燈的例子,就是紅燈停,綠燈行。

  現在生成一個線程,這個線程我讓它扮演紅綠燈,它每過一段時間就變成綠燈,又過一段時間變成紅燈,又變成黃燈。然后再生成3-5個線程作為車。車看見紅燈,它就停下來等着,如果說是綠燈,車子就走。所以就涉及到紅燈這個線程,紅綠燈的這個線程就跟車線程之前產生了依賴了。就是紅綠燈這個線程必須在綠燈的時候才能走,在紅燈的時候就立刻停下來。所以互相之前,一個線程會根據另外一個線程的狀態產生一些變化。類似這種場景的實現,就是:event,即事件。

1、事件的基礎內置函數

event = threading.Event()   # 設置一個事件的全局變量

event.is_set()# 判斷是否已經設置標志位。

event.wait()   # 沒有設置標志位的時候會阻塞,一遇到標志位就不會阻塞 #判斷是否已經設置標志位。

event.set()   # 設置標志位 ,標志位設置了,代表着綠燈,直接通行。

event.clear()   # 清除標志位,標志位被清空,代表紅燈,wait等待變綠燈。

2、紅綠燈例子

import threading
import time

event = threading.Event()  # 生成線程事件實例


def lighter():
    """
    模擬紅綠燈
    :return:
    """
    count = 0
    event.set()   # 先設置標志位,代表綠燈
    while True:
        if count > 5 and count < 10:   # 改成紅燈
            event.clear()    # 清除標志位,變成紅燈
            print("\033[41m red light is on ....\033[0m")
        elif count > 10:
            event.set()   # 創建標志位,變成綠燈
            count = 0
        else:
            print("\033[42m green light is on ....\033[0m")

        time.sleep(1)
        count += 1


def car(name):
    """
    模擬車子
    :param name:
    :return:
    """
    while True:
        if event.is_set():   # 有標志位,代表是綠燈
            print("{0} running ....".format(name))
            time.sleep(1)
        else:   # 如果不是綠燈就代表紅燈
            print("{0} sees red light ,waiting ....".format(name))
            event.wait()   # 阻塞
            print("\033[32m green light is on , start going ...\033[0m")


light = threading.Thread(target=lighter,)  # 啟動代表紅綠燈的線程
light.start()

car1 = threading.Thread(target=car, args=("car1",))  # 啟動代表車的線程
car1.start()

3、員工刷卡例子

員工進公司門要刷卡, 我們這里設置一個線程是“門”, 再設置幾個線程為“員工”,員工看到門沒打開,就刷卡,刷完卡,門開了,員工就可以通過。

import threading
import time
import random


def door():
    door_open_time_counter = 0
    while True:
        if door_swiping_event.is_set():
            print("\033[32;1m door opening....\033[0m")
            door_open_time_counter +=1

        else:
            print("\033[31;1m door closed...., swipe to open.\033[0m")
            door_open_time_counter = 0  # 清空計時器
            door_swiping_event.wait()

        if door_open_time_counter > 3:  # 門開了已經3s了,該關了
            door_swiping_event.clear()

        time.sleep(0.5)


def staff(n):

    print("staff [%s] is coming..." % n )
    while True:
        if door_swiping_event.is_set():
            print("\033[34;1m door is opened, passing.....\033[0m")
            break
        else:
            print("staff [%s] sees door got closed, swiping the card....." % n)
            print(door_swiping_event.set())
            door_swiping_event.set()
            print("after set ", door_swiping_event.set())
        time.sleep(0.5)


if __name__ == "__main__":

    door_swiping_event = threading.Event()  # 設置事件
    door_thread = threading.Thread(target=door)
    door_thread.start()

    for i in range(20):
        p = threading.Thread(target=staff, args=(i,))
        time.sleep(random.randrange(3))
        p.start()

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM