我有一个迭代器函数,它产生一个无限的整数流:
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吗?
答案 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!