協程是一種使用者态的輕量級線程,使用協程有衆多好處:
第一個好處是協程像一種在程式級别模拟系統級别的程序,由于是單線程,并且少了上下文切換,是以相對來說系統消耗很少,而且網上的各種測試也表明協程确實擁有驚人的速度。
第二個好處是協程友善切換控制流,這就簡化了程式設計模型。協程能保留上一次調用時的狀态(所有局部狀态的一個特定組合),每次過程重入時,就相當于進入了上一次調用的狀态。
第三個好處是協程的高擴充性和高并發性,一個CPU支援上萬協程都不是問題,是以很适合用于高并發處理。
協程也有缺點。
第一,協程的本質是一個單線程,不能同時使用單個CPU的多核,需要和程序配合才能運作在多CPU
上。
第二,有長時間阻塞的操作時不要用協程,因為可能會阻塞整個程式。
在 Pythongevent的協程中可以使用庫。 gevent也可以使用pip安裝:
pip install gevent
安裝完 gevent,就可以使用 gevent進行爬蟲了,代碼如下:
import gevent
from gevent.queue import Queue, Empty
import time
import requests
from gevent import monkey
link_list = []
# 把下面有可能有I0操作的單獨做上标記
monkey.patch_all() # 将IO轉為異步執行的函數
with open('alexa.txt', 'r') as file:
file_list = file.readlines()
for each in file_list:
link = each.replace('\n', '')
link_list.append(link)
def crawler(index):
process_id = 'Process--' + str(index)
while not workQueue.empty():
url = workQueue.get(timeout=2)
try:
r = requests.get(url, timeout=20)
print(process_id, workQueue.qsize(), r.status_code, url)
except Exception as e:
print(process_id, workQueue.qsize(), url, 'Error:', e)
def boss():
for url in link_list:
workQueue.put_nowait(url)
if __name__ == '__main__':
workQueue = Queue(1010)
gevent.spawn(boss).join()
start = time.time()
jobs = []
for i in range(10):
jobs.append(gevent.spawn(crawler, i))
gevent.joinall(jobs)
end = time.time()
print('gevent' + 'Queue多協程爬蟲的總時間為:', end - start)
print('Main Ended!')
在上述代碼中,我們首先使用了
from gevent import monkey
monkey. patch_all()
這樣可以實作爬蟲的并發能力,如果沒有這兩句,整個抓取過程就會變成依次抓取。 geventmonkey庫中的能把可能有l0操作的單獨做上标記,将1O變成可以異步執行的函數。我們還是用 Queue建立隊列,但是在
gevent中需要使用:gevent. spawn(boss).join()将隊列中加入的内容整合到 gevent中。接下來使用如下代碼建立多協程的爬蟲程式:
for i in range(10):
jobs.append(gevent.spawn(crawler, i))
gevent.joinall(jobs)
運作上述代碼,可以發現開了10個協程,爬蟲的速度變得非常快,多協程爬蟲能夠很好地支援高并發的
工作。