Подтвердить что ты не робот

Запросы Python с многопоточным

Я пытаюсь создать скребок с многопоточной функциональностью за два дня. Почему-то я все еще не мог справиться с этим. Сначала я попробовал обычный многопоточный подход с модулем потоковой передачи, но он был не быстрее, чем с использованием одного потока. Позже я узнал, что запросы блокируются, а многопоточный подход не работает. Поэтому я продолжал исследовать и узнавать о греках и 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()
4b9b3361

Ответ 1

Установите модуль grequests, который работает с gevent (requests не предназначен для async):

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:

Блокировка или неблокирование?

При использовании адаптера транспорта по умолчанию, Requests не предоставляет какой-либо неблокирующий IO. Свойство Response.content будет блокироваться до тех пор, пока весь ответ не будет загружен. Если вам требуется больше детализации, потоковые функции библиотеки (см. Потоковые запросы) позволяют вам получать меньшие количества ответов за раз. Однако эти вызовы будут по-прежнему блокироваться.

Если вас беспокоит использование блокировки ввода-вывода, есть много проектов, которые объединяют запросы с одной из инфраструктур асинхронности Python. Два отличных примера: grequests и requests-futures.

Использование этого метода дает мне заметное увеличение производительности с 10 URL-адресами: 0.877s vs 3.852s с помощью вашего исходного метода.