2013-11-20 10 views
6

Fikir basit: Paralel olarak birden çok HTTP isteği göndermem gerekiyor.Python 3'te birden çok HTTP isteği göndermenin en iyi yolu nedir?

Bunun için temel olarak birden çok iş parçacığı olan requests-futures kitaplığı kullanmaya karar verdim.

Şimdi yaklaşık 200 isteğim var ve hala oldukça yavaş (dizüstü bilgisayarımda yaklaşık 12 saniye sürüyor). Ayrıca yanıt jsonunu ayrıştırmak için bir geri arama kullanıyorum (kitaplık belgelerinde önerildiği gibi). Ayrıca, istek sayısının bir fonksiyonu olarak en uygun iplik sayısını belirlemek için bir başparmak kuralı var mı?

Temel olarak, bu istekleri daha fazla hızlandırabilir miyim diye merak ediyordum.

+0

Hangi sürüm python? Stdlib seçenekleriniz 2.7'den 3.3'e oldukça değişiyor. – roippi

+0

urllib + Threading modülünü önereceğim, ancak bağlandığınız paket aslında aynı şeyi yapıyor. İş parçacığı sayısı kadarıyla, dizüstü bilgisayarımda (MacBook Pro, 3.2 GHz işlemci, 16 GB RAM) bir problem olmadan 25 tane çalışıyorum. – BenDundee

+0

@roippi python kullanıyorum 3.3 –

cevap

6

python 3,3 kullandığınızdan, bağlı konu içerisinde bulamayacağınız bir stdlib çözümü önerecektir: @ njzk2: concurrent.futures.

Bu, yalnızca threading veya multiprocessing ilkelleriyle doğrudan çalışmaktan daha üst düzey bir etkileşmedir. Havuzlama ve zaman uyumsuz raporlama için bir Executor arabirimi alırsınız.

dokümanlar temelde durumuyla doğrudan uygulanabilir bir örnek var, bu yüzden sadece burada bırakın edeceğiz: Eğer bunu arzu Sen requests çağrıları ile urllib.request aramaları yerini alabilir

import concurrent.futures 
import urllib.request 

URLS = #[some list of urls] 

# Retrieve a single page and report the url and contents 
def load_url(url, timeout): 
    conn = urllib.request.urlopen(url, timeout=timeout) 
    return conn.readall() 

# We can use a with statement to ensure threads are cleaned up promptly 
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: 
    # Start the load operations and mark each future with its URL 
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} 
    for future in concurrent.futures.as_completed(future_to_url): 
     url = future_to_url[future] 
     try: 
      data = future.result() 
      # do json processing here 
     except Exception as exc: 
      print('%r generated an exception: %s' % (url, exc)) 
     else: 
      print('%r page is %d bytes' % (url, len(data))) 

. Açık nedenlerle, requests'u daha çok beğeniyorum.

API, şu şekilde gider: işlevinizin zaman uyumsuz yürütülmesini temsil eden bir grup Future nesnesi oluşturun. Daha sonra Future örnekleriniz üzerinde bir yineleme vermek için concurrent.futures.as_completed kullanın. Onları tamamlandıkça verecektir. Sorunuza gelince

:

Ayrıca

, isteklerin sayısının bir fonksiyonu olarak Uygun thread sayısına anlamaya Pratik bir kural var, herhangi var mı?

Başparmak, no. İnternet bağlantınızın hızı da dahil olmak üzere çok fazla şeye bağlıdır. Gerçekten, üzerinde çalıştığınız donanımın daha çok sahip olduğunuz istek sayısına bağlı olmadığını söyleyeceğim.

Neyse ki, max_workers kwarg'ı düzeltmek ve kendiniz test etmek oldukça kolaydır. 5 ya da 10 iş parçacığı ile başlayın, 5'lik artışlarla yükselin. Muhtemelen bir noktada performans platolarını fark edeceksiniz ve daha sonra ek iplikler eklemeye başlamanın artan paralelleşmenin marjinal kazanımını aştığı için azalmaya başlayacaksınız (bir kelime) .

+0

AWS makinelerde daha önce çalıştığım açık iş parçacıkları hakkında _are_ sınırlamaları var diyelim, ama dizüstü bilgisayarımda değil. Sorun burada özetlenmiştir: http://www.alak.cc/2011/11/python-threaderror-cant-start-new.html – BenDundee

+0

@roippi Orijinal gönderiimde saygı duyduğum istek-vadeli modülüne bir göz attınız mı? ? Aynı kodu hemen hemen uygular. –

+0

@NikolayDerkach hayır, ama bakma .. ha! Temel olarak yukarıdakileri bir API çağrısı haline getirir, ki bu oldukça hoş. Bununla ilgili bir problem, eğer yavaş/yanlış davranıyorsa, ince ayar yapmak için herhangi bir başvurunuz yoktur. Örneğin, yanlış gittiğinde yukarıdaki kodu daha kolay bir şekilde yapabilirsiniz. Her neyse, iyi şanslar :) – roippi