Python请求多线程

时间:2016-07-09 08:56:21

标签: python multithreading asynchronous python-requests gevent

过去两天我一直在尝试使用多线程功能构建一个刮刀。不知怎的,我仍然无法管理它。起初我尝试了使用线程模块的常规多线程方法,但它并不比使用单个线程快。后来我才知道请求是阻塞的,多线程方法并没有真正起作用。所以我一直在研究并发现了关于grequest和gevent的事情。现在我正在使用gevent运行测试,它仍然不比使用单个线程更快。我的编码错了吗?

以下是我班级的相关部分:

import gevent.monkey
from gevent.pool import Pool
import requests

gevent.monkey.patch_all()

class Test:
    def __init__(self):
        self.session = requests.Session()
        self.pool = Pool(20)
        self.urls = [...urls...]

    def fetch(self, url):

        try:
            response = self.session.get(url, headers=self.headers)
        except:
            self.logger.error('Problem: ', id, exc_info=True)

        self.doSomething(response)

    def async(self):
        for url in self.urls:
            self.pool.spawn( self.fetch, url )

        self.pool.join()

test = Test()
test.async()

1 个答案:

答案 0 :(得分:25)

安装适用于gevent的{​​{3}}(requests不适用于异步):

pip install grequests

然后将代码更改为:

import grequests

class Test:
    def __init__(self):
        self.urls = [
            'http://www.example.com',
            'http://www.google.com', 
            'http://www.yahoo.com',
            'http://www.stackoverflow.com/',
            'http://www.reddit.com/'
        ]

    def exception(self, request, exception):
        print "Problem: {}: {}".format(request.url, exception)

    def async(self):
        results = grequests.map((grequests.get(u) for u in self.urls), exception_handler=self.exception, size=5)
        print results

test = Test()
test.async()

这是requests项目的grequests module

  

阻止还是非阻止?

     

使用默认传输适配器,请求不提供任何类型的非阻塞IO。 Response.content属性将被阻止,直到整个响应被下载。如果您需要更多粒度,则库的流式传输功能(请参阅officially recommended)允许您一次检索较小数量的响应。但是,这些调用仍会阻止。

     

如果您担心使用阻塞IO,那么有很多项目将Requests与Python的异步框架结合起来。两个很好的例子是Streaming Requestsgrequests

使用此方法可以使用原始方法为10个网址带来显着的性能提升:0.877s3.852s