Python並行編程(三):多線程同步之semaphore(信號量)實現簡易生產者-消費者模型

什麼是信號量

semaphore信號量,其控制着對公共資源或者臨界區的訪問。信號量維護着一個計數器,指定可同時訪問資源或者進入臨界區的線程數。 semaphore是一個內置的計數器 每當調用acquire()時,內置計數器-1;若是計數器爲負數,即資源正在被佔用,須要掛起等待 每當調用release()時,內置計數器+1;增長到正數時,隊列中的第一個等待線程就能夠訪問共享資源了python

模擬Lock()鎖機制

若是咱們將計數器設置爲1即,第一次線程是不須要等待信號量的釋放的,參照上節代碼能夠進行對比:併發

import threading
import time
resoure = 0

count = 1000000

semaphore = threading.Semaphore(1)


def increment():
    global resoure
    for i in range(count):
        semaphore.acquire()
        resoure += 1
        semaphore.release()

def decerment():
    global resoure
    for i in range(count):
        semaphore.acquire()
        resoure -= 1
        semaphore.release()


increment_thread = threading.Thread(target=increment)
decerment_thread = threading.Thread(target=decerment)

increment_thread.start()
decerment_thread.start()

increment_thread.join()
decerment_thread.join()

print(resoure)

複製代碼

簡易生產者-消費者模型

import threading
import random
import time

semaphore = threading.Semaphore(0)

# 假設生產的資源
item_number = 0

# 消費者
def consumer():
    print('Consumer is waiting for Producer')

    # 等待獲取信號量
    semaphore.acquire()

    print('get the product , number is {}'.format(item_number))

# 生產者
def producer():
    global item_number

    # 模擬生產資源過程
    time.sleep(2)
    item_number = random.randint(1, 100)
    time.sleep(2)

    print('made the product , number is {}'.format(item_number))

    # 釋放信號量
    semaphore.release()

if __name__ == "__main__":
    for i in range(5):

        # 將生產者、消費者實例化爲線程
        thread_consumer = threading.Thread(target=consumer)
        thread_producer = threading.Thread(target=producer)

        thread_consumer.start()
        thread_producer.start()

        thread_consumer.join()
        thread_producer.join()

    print('consumer-producer example end.')

複製代碼

運行截圖以下: app

運行結果
咱們能夠看見兩個線程運行時的規律,即消費者必須等待生產者生產好商品(即釋放資源),消費者才能獲取消費資源(即訪問資源),其他時間消費者線程都處於掛起等待(等待信號量)。

利用信號量控制併發數量

利用semaphore咱們就能夠設置同時訪問某些共享資源的線程數量,即經過設設置信號量的值來控制線程同時訪問的數量,好比咱們能夠控制爬蟲程序訪問連接的線程數量(彷佛這樣能夠實現必定的異步),減小目標網站的壓力,同時信號量也支持上下文管理器:dom

import threading
import random
import time

# 信號量爲三即可以釋放的資源爲三次
semaphore = threading.Semaphore(3)      # 互斥鎖+隊列 至關於一個容器,容器裏同時最大能夠存在五個鑰匙,同時也只能有五個線程,
                                        # 誰先拿到並釋放後,下一個才能拿到鑰匙

# 假定url序號
order = 0

def spider():
    global order
    with semaphore:
        # 模擬採集過程
        time.sleep(2)
        order +=1
        
        print('{} is crawlering on {}th url'.format(threading.currentThread().getName(), order))
        time.sleep(2)
         
Threads = []
for i in range(10):
    t = threading.Thread(target=spider)
    Threads.append(t)
    t.start()
    
for t in Threads:
    t.join()

print('Spider end.')

複製代碼

運行截圖以下: 異步

運行結果
相關文章
相關標籤/搜索