python 64式: 第4式、eventlet協程實現併發
阿新 • • 發佈:2018-11-08
#!/usr/bin/env python # -*- coding: utf-8 -*- from datetime import datetime import eventlet eventlet.monkey_patch(all=True) from eventlet.green import urllib2 ''' 關鍵: 1 eventlet:協程(綠色執行緒),一個執行緒內的偽併發方式 原理:是執行序列,有獨立棧和區域性變數,與其他協程共享全域性變數 與執行緒區別:多個執行緒可同時執行,而同一時間內,只允許一個協程執行,所以無需考慮鎖 好處:協程執行順序由程式決定,若工作耗時,協程會讓出CPU,充分利用CPU效能。非阻塞。 本質:協程休息時會儲存當前暫存器,重新工作會恢復 適用: 一個用來處理和網路相關的python庫函式,而且可以通過協程來實現併發 參考文件: https://www.cnblogs.com/Security-Darren/p/4170031.html 2 綠化與猴子補丁 所謂”綠化”是指綠化後的Python環境支援綠色執行緒的執行模式。 Python原生的標準庫不支援eventlet這種綠色執行緒之間互相讓渡CPU控制權的執行模型, 為此eventlet開發者改寫了部分Python標準庫(自稱”補丁“)。 如果想在應用中使用eventlet,需要顯式地綠化自己要引入的模組。 猴子補丁,在執行時動態修改已有程式碼,而無需修改原始程式碼 使用:替換標準庫中的元件,例如socket 用法 import eventlet eventlet.monkey_patch() # 預設不加任何引數的情況下,是所有可能的module都會被patch。 monkey_patch(all=True,os=None, select=None, socket=None,thread=None,time=None,psycopg=None) 3 urllib2:用於抓取網頁並儲存到本地。把URL做為請求被髮送到服務端,讀取 服務端的響應資源 urllib2.urlopen(url,data,timeout) 返回值:instance data是傳送給服務端的內容 參考: https://docs.python.org/2/library/urllib2.html 4 eventlet.GreenPool() 作用:提供了對greenthread支援,提供已定數量的綠色執行緒,實際 就是綠色執行緒池 class eventlet.greenpool.GreenPool(size=1000) imap(function,* iterables) 等同於: itertools.imap(function, **iterable),在併發 和記憶體使用上等同於starmap() 用於:處理檔案 5 eventlet.GreenPile(size_or+pool=1000) GreenPile:用於表示抽象的IO相關任務 spawn(func, *args, **kw): 執行func在自己的綠色執行緒中,結果可以通過迭代 綠色管道 參考:http://eventlet.net/doc/modules/greenpool.html#eventlet.greenpool.GreenPool.spawn_n 6 不論是gevent還是eventlet,因為不存在實際的併發,響應時間和沒有併發區別不大。 所以所謂的併發應該是看 如果用了monkey_patch替換的模組換成併發的模組,才會帶來這個影響 總結: eventlet是通過將標準python模組替換為可併發的模組來實現併發 ''' URLS=["https://www.baidu.com/"] def timeHelper(func): def wrapper(*args, **kwargs): try: start = datetime.now() info = "############ Start at: %s ##########" % ( str(start)) print info result = func(*args, **kwargs) end = datetime.now() diff = end - start info = "##### End at: %s, cost time: %s #####" % ( str(end), str(diff)) print info return result except Exception as ex: info = "Exception type is %s, message is %s" % (ex.__class__.__name__, ex) print info return wrapper def getUrl(url): stream = urllib2.urlopen(url) result = stream.read() return result @timeHelper def batch(urls, batchNum): i = 0 results = [] tempUrls = [] for url in urls: tempUrls.append(url) if (i + 1) % batchNum == 0: result = validGreenPile(tempUrls) results.extend(result) tempUrls = [] i += 1 if tempUrls: result = validGreenPile(tempUrls) results.extend(result) return results @timeHelper def batchPool(urls, batchNum): i = 0 results = [] tempUrls = [] for url in urls: tempUrls.append(url) if (i + 1) % batchNum == 0: result = validGreenPool(tempUrls) results.extend(result) tempUrls = [] i += 1 if tempUrls: result = validGreenPool(tempUrls) results.extend(result) return results def validGreenPile(urls): pool = eventlet.GreenPool() pile = eventlet.GreenPile(pool) for url in urls: pile.spawn(getUrl, url) results = [] for pl in pile: results.append(pl) return results def validGreenPool(urls): pool = eventlet.GreenPool() results = [] for result in pool.imap(getUrl, urls): results.append(result) return results def getUrls(times): urls = [] for i in range(times): urls.extend(URLS) return urls def process(): urls = getUrls(200) batchPool(urls, 100) if __name__ == "__main__": process()