Python 多線程的事件監控

沙拉

設想這樣一個場景:

你創建了 10 個子線程,每個子線程分別爬一個網站,一開始所有子線程都是阻塞等待。一旦某個事件發生:例如有人在網頁上點了一個按鈕,或者某人在命令行輸入了一個命令,10 個爬蟲同時開始工作。

肯定有人會想到用 Redis 來實現這個開關:所有子線程全部監控 Redis 中名爲 start_crawl 的字符串,如果這個字符串不存在,或者爲 0,那麼就等待 1 秒鐘,再繼續檢查。如果這個字符串爲 1,那麼就開始運行。

代碼片段可以簡寫爲:

import time
import redis

client = redis.Redis()
while client.get('start_crawl') != 1:
    print('繼續等待')
    time.sleep(1)

這樣做確實可以達到目的,不過每一個子線程都會頻繁檢查 Redis。

實際上,在 Python 的多線程中,有一個Event模塊,天然就是用來實現這個目的的。

Event 是一個能在多線程中共用的對象,一開始它包含一個爲False的信號標誌,一旦在任一一個線程裏面把這個標記改爲True,那麼所有的線程都會看到這個標記變成了True

我們通過一段代碼來說明它的使用方法:

import threading
import time

class spider(threading.Thread):
    def __init__(self, n, event):
        super().__init__()
        self.n = n
        self.event = event

    def run(self):
        print(f'第{self.n}號爬蟲已就位!')
        self.event.wait()
        print(f'信號標記變爲True!!第{self.n}號爬蟲開始運行')

eve = threading.Event()
for num in range(10):
    crawler = spider(num, eve)
    crawler.start()

input('按下回車鍵,啓動所有爬蟲!')
eve.set()
time.sleep(10)

運行效果如下圖所示:

在這段代碼中,線程spider在運行以後,會運行到self.event.wait()這一行,然後 10 個子線程會全部阻塞在這裏。而這裏的self.event,就是主線程中eve = threading.Event()生成的對象傳入進去的。

在主線程裏面,當執行了eve.set()後,所有子線程的阻塞會被同時解除,於是子線程就可以繼續運行了。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/po6wGCF_Ww8xDJKgEywZ0g