關於封裝了gevent的request grequest庫的使用與討論

最近迷上了gevent因此研究不少gevent相關的東西。html

可是我如今不想寫相關gevent和greenlet的東西。由於這一塊內容實在太多太大太雜,我本身也尚未徹底弄明白,因此等我徹底搞清楚測試也測試過了以後。我會寫一篇比較系統一點的東西來把我最近研究,和測試過的東西都展示出來。python

今天先寫一個基於gevent開發的requests庫,grequests的使用。json

爲何會有地方使用到grequests呢?服務器

首先是對io密集型的需求處理。首先咱們都知道,如咱們去請求一個網站上的數據,正常來講咱們會一條一條的跑,例如這樣。多線程

import requests

url = 'http://www.baidu.com'
x = request.get(url)
print x

若是是多個網站的請求 咱們可能會使用一個循環以此遍歷list url對象。併發

可是這樣就會造一個常見的性能問題。例如中間有一個請求卡住了,或者一些狀況致使一個請求長時間沒有返回,因爲咱們的同步請求模式,在獲得返回以前咱們可能會長時間處於一個io阻塞的狀態。這樣顯而易見,若是有100個請求,不論是性能仍是效率確定都是慢得沒得說的。異步

 

因而咱們纔會想要用一種並行的思路去解決相似的問題。若是咱們同時開啓100個請求,那麼最差的狀況也就等最後返回的那個傢伙返回就能夠結束全部的請求了。性能提高是n倍,幾乎越多請求異步操做的優點也就越明顯。可是這裏就要注意了,通常咱們不會同步開啓那麼多請求去訪問,由於若是咱們開啓那麼多訪問去同時命中對方一臺服務器(假設是本身的生產服務器)那麼會形成很是大的壓力,因此這裏咱們還能夠設置map()的參數將size這個決定並行數量的參數設置成你認爲合理的並行值便可。async

    rs = (grequests.get(u, proxies=proxies) for u in urls)
    grequests.map(rs, size=10)

 

可是要注意一點,因爲python裏面的全局鎖的關係,並不推薦使用多線程這樣的僞並行的方式。雖然coroutines也是僞並行的方式(即線性請求,當其中一個請求遇到io等待的時候切換到另一個coroutines繼續運行等到io返回以後再接收信息,避免長時間的等待和阻塞)因此今天介紹的grequests庫就能夠在python裏使用gevent基於coroutines(協程)解決這個問題。性能

 

這裏演示使用代碼,異常簡單就可使你的請求性能提高數倍。測試

import grequests
import requests
import cProfile

urls = [
    'http://www.xiachufang.com/downloads/baidu_pip/2016030101.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030102.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030103.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030104.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030105.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030106.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030107.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030108.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030109.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030110.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030111.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030112.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030113.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030114.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030115.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030116.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030117.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030118.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030119.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030120.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030121.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030122.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030123.json',
    'http://www.xiachufang.com/downloads/baidu_pip/2016030200.json',
]
def haha(urls):
    rs = (grequests.get(u) for u in urls)
    return grequests.map(rs)

cProfile.run("haha(urls)")

def hehe(urls):
    hehe = [requests.get(i) for i in urls]
    return hehe

cProfile.run("hehe(urls)")

下面貼出請求所用時間數據 僅供參考。

使用異步在24個請求的平均耗時測試10次計算 平均花費130毫秒

      2/1    0.000    0.000    0.132    0.132 coventry.py:651(haha)

 

在使用同步普通的request庫請求的狀況下 一樣測試10次 平均花費900毫秒 若是中途遇到有單個連接不穩或者超時甚至會花費1秒

 2/1    0.000    0.000    1.149    1.149 coventry.py:657(hehe)

 

總結:

在io密集,等待io時間長的請求量級越大的狀況,這樣的性能提高越是明顯,使用併發或者協程至少提高性能5倍以上咱們越是應該使用異步或並行操做來減小io的等待時間。python比較有效和高效的處理方案我以爲非coroutines(協程)莫屬了,而相關庫最好用的又是gevent,因此很是值得深刻研究下去,一探究竟。使用相似操做減小io等待,提高整個業務性能。

 

refrence:

http://stackoverflow.com/questions/16015749/in-what-way-is-grequests-asynchronous 

http://johndangerthornton.blogspot.com/2015/02/grequests-examples.html

http://stackoverflow.com/questions/21978115/using-grequests-to-make-several-thousand-get-requests-to-sourceforge-get-max-r

相關文章
相關標籤/搜索