semaphore
信號量,其控制着對公共資源或者臨界區的訪問。信號量維護着一個計數器,指定可同時訪問資源或者進入臨界區的線程數。 semaphore是一個內置的計數器 每當調用acquire()時,內置計數器-1;若是計數器爲負數,即資源正在被佔用,須要掛起等待 每當調用release()時,內置計數器+1;增長到正數時,隊列中的第一個等待線程就能夠訪問共享資源了python
若是咱們將計數器設置爲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.')
複製代碼
運行截圖以下: 異步