多处理。池和速率限制

时间:2015-09-21 16:58:49

标签: python multiprocessing pool

我正在制作一些api请求,限制为每秒20次。至于得到答案,等待时间约为0.5秒我想使用multiprocessing.Pool.map并使用这个装饰器 rate-limiting 所以我的代码看起来像

    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次请求,则装饰器不能按预期工作。 在这种情况下我还能用什么?

更新

对于任何寻找使用池的人都要记得关闭它,否则你将使用所有的RAM

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

更新2

我发现像WebRequestManager这样的东西可以解决问题。问题是多处理不起作用.Pool有19-20个进程,因为时间存储在运行请求时需要调用的类上。

1 个答案:

答案 0 :(得分:0)

你的缩进在上面是不一致的,这使得回答这个问题变得更加困难,但是我会采取刺。

看起来你是限制错误的事情;如果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))