简体   繁体   English

Python并发期货大量投入闲置

[英]Python concurrent futures large number of inputs sit idle

I am processing large number of files (tens of millions) using Python's concurrent.futures.我正在使用 Python 的 concurrent.futures 处理大量文件(数千万)。 Issuing a small number of inputs work fine, however when the input size increases, the processes just don't start.发出少量输入工作正常,但是当输入大小增加时,进程就不会启动。 Below code executes only when input size is small, eg 20_000.以下代码仅在输入大小较小时执行,例如 20_000。

import concurrent
import math

def some_math(x):
    y = 3*x**2 + 5*x + 7
    return math.log(y)

inputs = range(1_000_000)
results = []

with concurrent.futures.ProcessPoolExecutor() as executor:
    for result in executor.map(some_math, inputs):
        results.append(result)

I have tried to overcome this by submitting jobs in smaller batches as below:我试图通过如下小批量提交作业来克服这个问题:

import concurrent
import math
    
def some_math(x):
    y = 3*x**2 + 5*x + 7
    return math.log(y)

up_to = 220_000
batch_size = 20_000
results = []
for idx in range(0, up_to, batch_size):
    low = idx
    high = min(low + batch_size, up_to)
    
    inputs = range(low, high)
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for result in executor.map(some_math, inputs):
            results.append(result)

But again, it either does not start at all, or gets stuck after a few iterations of the outer for loop.但同样,它要么根本不启动,要么在外部 for 循环的几次迭代后卡住。

My Python version is 3.10.7.我的Python版本是3.10.7。 What is the issue here?这里的问题是什么?

you need to take advantage of the chunksize parameter of the map function, the pool is simply a pipe with a shared lock, and having 10 or more processes contending over that lock is going to be very slow.您需要利用map function 的chunksize参数,池只是一个带有共享锁的 pipe,并且有 10 个或更多进程争用该锁将会非常慢。

using a large chunksize reduces this contention, as each process is going to grab a larger chunk off the queue each time it takes the lock.使用较大的块大小可以减少这种争用,因为每个进程每次获取锁时都会从队列中获取更大的块。

import concurrent.futures
import math

def some_math(x):
    y = 3*x**2 + 5*x + 7
    return math.log(y)
if __name__ == "__main__":
    inputs = range(1_000_000)
    results = []

    with concurrent.futures.ProcessPoolExecutor() as executor:
        for result in executor.map(some_math, inputs, chunksize=10_000):
            results.append(result)

in the above code the lock will only be locked 100 times instead of 1_000_000 times, and you get much less context switching.在上面的代码中,锁只会被锁定 100 次而不是 1_000_000 次,并且上下文切换要少得多。

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

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