无限迭代器上的Python线程/进程池?

时间:2017-01-22 01:54:17

标签: python multithreading threadpool python-multiprocessing

我有一个迭代器函数,它产生一个无限的整数流:

def all_ints(start=0):
  yield start
  yield all_ints(start+1)

我想让一个线程池或进程池一次对$ POOLSIZE进行计算。每个进程都可能将结果保存到某个共享数据结构中,因此我不需要进程/线程函数的返回值。在我看来,使用python3 Pool可以达到这个目的:

# dummy example functions
def check_prime(n):
  return n % 2 == 0

def store_prime(p):
    ''' synchronize, write to some shared structure'''
    pass

p = Pool()

for n in all_ints():
    p.apply_async(check_prime, (n,), callback=store_prime)

但是当我运行这个时,我得到一个python进程,它只是不断地使用更多内存(而不是来自迭代器,可以运行数天)。如果我存储了所有apply_async调用的结果,我会期望这种行为,但我不是。

我在这里做错了什么?或者我应该使用的线程池中有另一个API吗?

1 个答案:

答案 0 :(得分:3)

我认为你正在寻找Pool.imap_unordered,它使用池化进程将函数应用于迭代器产生的元素。其参数chunksize允许您指定迭代器中每个步骤中传递给池的项目数。

另外,我会避免使用IPC的任何共享内存结构。只需让发送到池中的“昂贵”函数返回您需要的信息,然后在主过程中处理它。

这是一个例子(我在200,000个结果之后中止;如果你删除那个部分,你会看到这些过程在固定数量的RAM中“永远地”工作):

from multiprocessing import Pool
from math import sqrt
import itertools
import time

def check_prime(n): 
    if n == 2: return (n, True)
    if n % 2 == 0 or n < 2: return (n, False)
    for i in range(3, int(sqrt(n))+1, 2):
        if n % i == 0: return (n, False)
    return (n, True)    

def main():
    L = 200000   # limit for performance timing 
    p = Pool()
    n_primes = 0
    before = time.time()
    for (n, is_prime) in p.imap_unordered(check_prime, itertools.count(1), 1000):
        if is_prime:
            n_primes += 1
            if n_primes >= L: 
                break
    print("Computed %d primes in %.1fms" % (n_primes, (time.time()-before)*1000.0))
if __name__ == "__main__":
    main()

我的英特尔酷睿i5(2核,4线程)输出:

Computed 200000 primes in 15167.9ms

如果我将其更改为Pool(1),则输出,因此只使用1个子流程:

Computed 200000 primes in 37909.2ms

HTH!