繁体   English   中英

多重处理池和速率限制

[英]multiprocessing.Pool and Rate limit

我正在发出一些API请求,这些请求限制为每秒20个。 为了得到答案,等待时间约为0.5秒,我以为使用multiprocessing.Pool.map并使用此装饰器限速,所以我的代码看起来像

def fun(vec):
        #do stuff

def RateLimited(maxPerSecond):
    minInterval = 1.0 / float(maxPerSecond)
    def decorate(func):
        lastTimeCalled = [0.0]
        def rateLimitedFunction(*args,**kargs):
            elapsed = time.clock() - lastTimeCalled[0]
            leftToWait = minInterval - elapsed
            if leftToWait>0:
                time.sleep(leftToWait)
            ret = func(*args,**kargs)
            lastTimeCalled[0] = time.clock()
            return ret
        return rateLimitedFunction
    return decorate

@RateLimited(20)
def multi(vec):
    p = Pool(5)   
    return p.map(f, vec)

我有4个核心,该程序运行良好,与循环版本相比,时间有所改善。 此外,当Pool参数为4,5,6时,它可以工作,而Pool(6)的时间更短,但是当我使用7+时,会出现错误(我猜每秒连接太多)。

然后,如果我的函数更复杂并且可以执行1-5请求,则装饰器将无法正常工作。 在这种情况下,我还能使用什么?

更新

对于任何想要使用的人,Pool都记得要关闭它,否则您将使用所有RAM

def multi(vec):
    p = Pool(5)   
    res=p.map(f, vec)
    p.close()
    return res

更新2

我发现像这样的WebRequestManager可以解决问题。 问题在于不适用于多处理。 具有19-20个进程的池,因为时间存储在运行请求时需要调用的类中。

上方的缩进不一致,因此很难回答,但我会采取措施。

看来您正在限制错误的事情; 如果应该限制f则需要将调用限制为f ,而不是对multi的调用。 在派遣到Pool事务中执行此操作将不起作用,因为分叉的工作人员将各自独立地进行限制(分叉的进程将独立跟踪自上次调用以来的时间)。

最简单的方法是限制Pool从中拉出的迭代器产生结果的速度。 例如:

import collections
import time
def rate_limited_iterator(iterable, limit_per_second):
    # Initially, we can run immediately limit times
    runats = collections.deque([time.time()] * limit_per_second)
    for x in iterable:
        runat, now = runats.popleft(), time.time()
        if now < runat:
            time.sleep(runat - now)
        runats.append(time.time() + 1)
        yield x

def multi(vec):
    p = Pool(5)
    return p.map(f, rate_limited_iterator(vec, 20))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM