2012-02-29 73 views
16

此代碼:如何啓用請求異步模式?

import sys 

import gevent 
from gevent import monkey 

monkey.patch_all() 

import requests 
import urllib2 

def worker(url, use_urllib2=False): 
    if use_urllib2: 
     content = urllib2.urlopen(url).read().lower() 
    else: 
     content = requests.get(url, prefetch=True).content.lower() 
    title = content.split('<title>')[1].split('</title>')[0].strip() 

urls = ['http://www.mail.ru']*5 

def by_requests(): 
    jobs = [gevent.spawn(worker, url) for url in urls] 
    gevent.joinall(jobs) 

def by_urllib2(): 
    jobs = [gevent.spawn(worker, url, True) for url in urls] 
    gevent.joinall(jobs) 

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests") 
    print 'by requests: %s seconds'%t.timeit(number=3) 
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2") 
    print 'by urllib2: %s seconds'%t.timeit(number=3) 
    sys.exit(0) 

這樣的結果:

by requests: 18.3397213892 seconds 
by urllib2: 2.48605842363 seconds 

嗅探器,它看起來這樣:

描述:前5個請求被請求庫sended,未來5個請求是由urllib2庫發送。 紅色 - 是工作凍結的時間,黑暗 - 當數據接收... wtf ?!

如果套接字庫補丁和庫必須工作相同,它將會怎樣? 如何在沒有requests.async的情況下使用請求進行異步工作?

+0

你能一點點進一步解釋問題了嗎?爲什麼你不想使用requests.async模塊? – Phani 2012-03-01 06:12:28

+0

請求不工作異步。爲什麼?我不希望使用requests.async,因爲它包含使用不良接口,也不會異步工作。看圖像,有工作請求和urllib2。 – user1239798 2012-03-01 12:16:54

+1

請參閱http://stackoverflow.com/questions/9110593/asynchronous-requests-with-python-requests和https://github.com/kennethreitz/grequests。 – 2013-02-08 12:34:20

回答

14

對不起肯尼斯·賴茨。他的圖書館非常棒。

我很蠢。我需要像這樣爲httplib選擇猴子補丁:

gevent.monkey.patch_all(httplib=True) 

因爲缺省情況下,httplib的補丁被禁用。

+11

無效:ValueError:不再提供gevent.httplib,httplib必須爲False – mamcx 2013-02-28 21:58:13

+1

使用grequests(by @KennethReitz)。它主要覆蓋主要動詞,並繼承其餘部分。 – 2014-09-27 19:51:03

2

我在我的機器上運行了您的代碼(python 2.7.1,gevent 0.13.0,requests 0.10.6)。事實證明,使用請求模塊的時間總是快一兩秒。你使用什麼版本?升級可能只是爲您解決問題。

by requests: 3.7847161293 seconds 
by urllib2: 4.92611193657 seconds 

by requests: 2.90777993202 seconds 
by urllib2: 7.99798607826 seconds 
+0

我使用的是這個版本:python 2.7.2.5,gevent 0.13.6,請求0.10.6 – user1239798 2012-03-01 21:28:43

+0

你的版本更高級,所以這真的很奇怪。我發佈了另一個答案,可能會對你有所幫助。 – Phani 2012-03-01 23:01:58

7

正如肯尼思指出,還有一點我們能做的就是讓requests模塊處理異步的一部分。我已經相應地修改了你的代碼。對我而言,結果一致表明requests模塊的性能好於urllib2

這樣做意味着我們不能「回調」回調部分。但這應該沒問題,因爲只有在請求/響應延遲的情況下,HTTP請求才能獲得主要收益。

import sys 

import gevent 
from gevent import monkey 

monkey.patch_all() 

import requests 
from requests import async 
import urllib2 

def call_back(resp): 
    content = resp.content 
    title = content.split('<title>')[1].split('</title>')[0].strip() 
    return title 

def worker(url, use_urllib2=False): 
    if use_urllib2: 
     content = urllib2.urlopen(url).read().lower() 
     title = content.split('<title>')[1].split('</title>')[0].strip() 

    else: 
     rs = [async.get(u) for u in url] 
     resps = async.map(rs) 
     for resp in resps: 
      call_back(resp) 

urls = ['http://www.mail.ru']*5 

def by_requests(): 
    worker(urls) 
def by_urllib2(): 
    jobs = [gevent.spawn(worker, url, True) for url in urls] 
    gevent.joinall(jobs) 

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests") 
    print 'by requests: %s seconds'%t.timeit(number=3) 
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2") 
    print 'by urllib2: %s seconds'%t.timeit(number=3) 
    sys.exit(0) 

這裏是我的結果之一:

by requests: 2.44117593765 seconds 
by urllib2: 4.41298294067 seconds 
+0

嗨!感謝對我的問題感興趣。我已經執行了你的代碼,並更新了第一篇文章的圖片,以顯示你的代碼如何工作。 – user1239798 2012-03-02 00:37:48

+0

這是工作結果:按請求:25.532893147秒 by urllib2:9.65230888283秒 – user1239798 2012-03-02 00:45:07

+0

恐怕我不能複製你的問題。我將gevent升級到0.13.6,並在兩臺不同的機器上嘗試過。但'request'模塊異步工作。僅供參考,我在Ubuntu 11.04和11.10上嘗試過。 – Phani 2012-03-02 04:40:28