2013-12-17 5 views
6

APIに何千もの呼び出しを行い、応答が遅くて数十秒かかるとします。唯一の制限は、最大で1秒あたり1回のリクエストを行うことができることです。これを行う最善の方法は何ですか?私は次のコードが動作すると思うが、私は何とかスレッドライブラリをうまく利用できるはずです。あなたは確実にしたい場合はPythonスレッドを使用して速度の遅いAPIへの呼び出しを数千回行う

from concurrent.futures import ThreadPoolExecutor 
with ThreadPoolExecutor(max_workers=5) as executor: 
    for work in work_list: 
     executor.submit(work_function, work) 

:私はこのように、あなたは固定サイズのスレッドプールを使用してジョブの束を実行したい場合は、あなたがconcurrent.futures.ThreadPoolExecutorを使用することができますのpython 3.3

last_job = datetime.now() 
for work in work_list: 
    while (datetime.now()-last_job).total_seconds() < 1 or threading.active_count() >= max_threads: 
     time.sleep(.1) 
    threading.Thread(target=work_function, args=[work]).start() 
    last_job = datetime.now() 
+0

私はあなたが作ることができるという権利を取得しました1秒ごとにリクエストするので、最初のクエリ結果が20秒間待つ間に、別の19個のインスタンスをインスタンス化できますか?それらの追加の19の質問は、最初のものに対する応答を遅くしないでしょうか? – alko

+0

セロリを使用してジョブをキューに入れ、レート制限を設定するのはなぜですか? – adam

+1

@adamはこの仕事のために少し残虐ではありませんか? – alko

答えて

11

を使用しています最大で1つのAPIコールを1秒間行うと、work_functionの内部からこれを行う必要があります。スレッドが使用可能になるのを待っているジョブがどれくらい待っているかわからないので、ジョブをサブミットするときには実行できません。

それが私だったら、それは再利用可能だように、私は独自のクラスにコードをレート制限を置くところ:

from collections import Iterator 
from threading import Lock 
import time 

class RateLimiter(Iterator): 
    """Iterator that yields a value at most once every 'interval' seconds.""" 
    def __init__(self, interval): 
     self.lock = Lock() 
     self.interval = interval 
     self.next_yield = 0 

    def __next__(self): 
     with self.lock: 
      t = time.monotonic() 
      if t < self.next_yield: 
       time.sleep(self.next_yield - t) 
       t = time.monotonic() 
      self.next_yield = t + self.interval 

api_rate_limiter = RateLimiter(1) 

def work_function(work): 
    next(api_rate_limiter) 
    call_api(...) 

time.monotonicはPython 3.3で導入されました。古いバージョンのPythonあなたは、これがすぎるスリープを起こさないようにする必要がありますので、あなたがtime.timeを使用することができますが、ときに、システムクロックの変更、これは逆方向にジャンプすることができますで:

   time.sleep(min(self.next_yield - t, self.interval)) 
+1

これは美しく動作します、ありがとうございます。 –

関連する問題