经过大量研究,我不确定最佳做法是什么,我的想法是否合适?
我想访问一个API,将我可以拨打的总呼叫数限制为每分钟50次。
我的程序有多个线程独立运行。
如何限制我的程序保持低于阈值?
我的想法是创建一个队列,每隔X秒向它添加一个东西,其中X = thread_count / allowed_calls * 60。然后,需要一个单独的线程来处理这些请求。 (以及定期添加的单独线程)
对于这样的事情,最佳做法是什么?有没有办法实现这一点,而不需要为每个小功能提供完全独立的线程?
答案 0 :(得分:2)
为什么不创建一个使用内部变量来控制呼叫次数和第一次呼叫的类?
从中删除此代码 https://github.com/lucjon/Py-StackExchange/blob/master/stackexchange/web.py
基本上,它检查您是否拥有超过所需的呼叫数量,如果是这种情况则停止。 如果您正在使用多线程(如池),请将函数请求作为要执行的函数传递。
class WebRequestManager(object):
# When we last made a request
window = datetime.datetime.now()
# Number of requests since last throttle window
num_requests = 0
def request(self, url, params):
now = datetime.datetime.now()
# Before we do the actual request, are we going to be throttled?
def halt(wait_time):
if self.throttle_stop:
raise TooManyRequestsError()
else:
# Wait the required time, plus a bit of extra padding time.
time.sleep(wait_time + 0.1)
if (now - WebRequestManager.window).seconds >= 1:
WebRequestManager.window = now
WebRequestManager.num_requests = 0
WebRequestManager.num_requests += 1
if WebRequestManager.num_requests > 30:
halt(5 - (WebRequestManager.window - now).seconds)
request = urllib.request.Request(url)
...
答案 1 :(得分:1)
您可以使用限制调用的装饰器:
import time, threading
# make it work nice across threads
def RateLimited(max_per_second):
'''
Decorator that make functions not be called faster than
'''
lock = threading.Lock()
minInterval = 1.0 / float(max_per_second)
def decorate(func):
lastTimeCalled = [0.0]
def rateLimitedFunction(args,*kargs):
lock.acquire()
elapsed = time.clock() - lastTimeCalled[0]
leftToWait = minInterval - elapsed
if leftToWait>0:
time.sleep(leftToWait)
lock.release()
ret = func(args,*kargs)
lastTimeCalled[0] = time.clock()
return ret
return rateLimitedFunction
return decorate
然后使用装饰器:
@RateLimited(2) # 2 per second at most
def PrintNumber(num):
print num
if __name__ == "__main__":
print "This should print 1,2,3... at about 2 per second."
for i in range(1,100):
PrintNumber(i)