J'ai essayé de construire un grattoir avec une fonctionnalité multithreading depuis deux jours. D'une certaine manière, je ne pouvais toujours pas y arriver. Au début, j'ai essayé une approche multithreading régulière avec un module de threading mais ce n'était pas plus rapide que d'utiliser un seul thread. Plus tard, j'ai appris que les demandes bloquaient et que l'approche multithreading ne fonctionnait pas vraiment. J'ai donc continué mes recherches et découvert les grèves et les événements. Maintenant, je lance des tests avec gevent et ce n'est toujours pas plus rapide que d'utiliser un seul thread. Mon codage est-il incorrect?
Voici la partie pertinente de ma classe:
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()
Installez le module grequests
qui fonctionne avec gevent
(requests
n'est pas conçu pour async):
pip install grequests
Modifiez ensuite le code en quelque chose comme ceci:
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()
C'est officiellement recommandé par le projet requests
:
Blocage ou non-blocage?
Avec l'adaptateur de transport par défaut en place, Requests ne fournit aucun type d'E/S non bloquant. Le
Response.content
la propriété sera bloquée jusqu'à ce que la réponse complète ait été téléchargée. Si vous avez besoin de plus de granularité, les fonctionnalités de streaming de la bibliothèque (voir Demandes de streaming ) vous permettent de récupérer de plus petites quantités de réponse à la fois. Cependant, ces appels seront toujours bloqués.Si vous êtes préoccupé par l'utilisation du blocage des E/S, il existe de nombreux projets qui combinent des demandes avec l'un des cadres d'asynchronicité de Python. Deux excellents exemples sont
grequests
etrequests-futures
.
L'utilisation de cette méthode me donne une augmentation notable des performances avec 10 URL: 0.877s
contre 3.852s
avec votre méthode d'origine.