2012-02-29 77 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