我有一个我需要从中获取数据的API的〜300K URL列表。
API限制为每秒100个调用。
我已经为异步创建了一个类,但是它正在快速运行,并且在API上出现错误。
如何降低异步速度,以便每秒可以进行100个呼叫?
import grequests
lst = ['url.com','url2.com']
class Test:
def __init__(self):
self.urls = lst
def exception(self, request, exception):
print ("Problem: {}: {}".format(request.url, exception))
def async(self):
return grequests.map((grequests.get(u) for u in self.urls), exception_handler=self.exception, size=5)
def collate_responses(self, results):
return [x.text for x in results]
test = Test()
#here we collect the results returned by the async function
results = test.async()
response_text = test.collate_responses(results)
答案 0 :(得分:2)
我采取的第一步是创建一个对象,该对象每t ms最多可以分配n个硬币。
import time
class CoinsDistribution:
"""Object that distribute a maximum of maxCoins every timeLimit ms"""
def __init__(self, maxCoins, timeLimit):
self.maxCoins = maxCoins
self.timeLimit = timeLimit
self.coin = maxCoins
self.time = time.perf_counter()
def getCoin(self):
if self.coin <= 0 and not self.restock():
return False
self.coin -= 1
return True
def restock(self):
t = time.perf_counter()
if (t - self.time) * 1000 < self.timeLimit:
return False
self.coin = self.maxCoins
self.time = t
return True
现在,我们需要一种强制函数仅在他们可以得到硬币时才被调用的方法。 为此,我们可以编写一个装饰函数,可以像这样使用:
@limitCalls(callLimit=1, timeLimit=1000)
def uniqFunctionRequestingServer1():
return 'response from s1'
但是有时候,有多个函数正在调用请求同一台服务器的请求,因此我们希望它们从相同的CoinsDistribution对象获取硬币。 因此,装饰器的另一种用途是通过提供CoinsDistribution对象:
server_2_limit = CoinsDistribution(3, 1000)
@limitCalls(server_2_limit)
def sendRequestToServer2():
return 'it worked !!'
@limitCalls(server_2_limit)
def sendAnOtherRequestToServer2():
return 'it worked too !!'
我们现在必须创建装饰器,它可以使用CoinsDistribution对象或足够的数据来创建一个新的装饰器。
import functools
def limitCalls(obj=None, *, callLimit=100, timeLimit=1000):
if obj is None:
obj = CoinsDistribution(callLimit, timeLimit)
def limit_decorator(func):
@functools.wraps(func)
def limit_wrapper(*args, **kwargs):
if obj.getCoin():
return func(*args, **kwargs)
return 'limit reached, please wait'
return limit_wrapper
return limit_decorator
就完成了!现在,您可以限制使用的任何API的调用次数,并且可以构建字典来跟踪您的CoinsDistribution对象(如果必须管理很多对象(以不同的API端点或不同的API))。
注意:如果没有可用的硬币,在这里我选择返回一条错误消息。您应该根据自己的需要调整这种行为。
答案 1 :(得分:1)
您只需跟踪已过去了多少时间,然后决定是否要执行更多请求。
这将每秒打印100个数字,例如:
from datetime import datetime
import time
start = datetime.now()
time.sleep(1);
counter = 0
while (True):
end = datetime.now()
s = (end-start).seconds
if (counter >= 100):
if (s <= 1):
time.sleep(1) # You can keep track of the time and sleep less, actually
start = datetime.now()
counter = 0
print(counter)
counter += 1
答案 2 :(得分:-2)
This其他问题确切显示了如何执行此操作。顺便说一句,您通常需要的是节流。