python 池工作者可以从初始化返回值吗?

时间:2021-02-02 21:31:26

标签: python multiprocessing

TL;DR 我想在池完成处理后收集每个工人的全局变量中累积的数据

描述我认为我缺少的东西

由于我是多处理的新手,我不知道存在的所有功能。我正在寻找一种方法让工人返回它初始化的值(在对该值进行数百万次操作之后)。然后,我希望在程序结束时,当所有“工作”完成后,我可以收集并合并所有这些值。

import multiprocessing as mp
from collections import defaultdict, Counter
from customtools import load_regexes #, . . .
import gzip
import nltk

result_dict = None
regexes = None

def create_worker():
    global result_dict
    global regexes
    result_dict = defaultdict(Counter) # I want to return this at the end
    # these are a bunch of huge regexes
    regexes = load_regexes()

这些函数代表了我加载和处理数据的方式。数据是一个包含文章的大 gzip 文件。

def load_data(semaphore):
    with gzip.open('some10Gbfile') as f:
        for line in file:
            semaphore.acquire()
            yield str(line, 'utf-8')

def worker_job(line):
    global regexes
    global result_dict
    hits = defaultdict(Counter)
    for sent in nltk.sent_tokenize(line[3:]):
        for rename, regex in regex.items():
            for hit in regex.finditer(sent):
                hits[rename][hit.group(0)]+=1
    # and more and more... results = _filter(_extract(hits))
    # store some data in results_dict here . . .
    return filtered_hits

Class ResultEater():
    def __init__(self):
        self.wordscounts=defaultdict(Counter)
        self.filtered=Counter()

def eat_results(self, filte red_hits):
    for k, v in filte.items():
        for i, c in v.items():
            self.wordscount[k][i]+=c

这是主程序

if __name__ == '__main__':
    pool = mp.Pool(mp.cpu_count(), initializer=create_worker)

    semaphore = mp.Semaphore(50)
    loader = load_data(semaphore)
    
    results = ResultEater()
    for intermediate_result in pool.imap_unordered(worker_job, loader, chunksize=10):
        results.eat_results(intermediate_result)
        semaphore.release()

    # results.eat_workers(the_leftover_workers_or_something)
    results.print()

1 个答案:

答案 0 :(得分:1)

我真的不认为我完全理解增量返回数据是不够的,但似乎您需要某种终结函数来发送类似于初始化函数的数据。不幸的是,我认为 mp.Pool 不存在这种事情,因此它需要您使用一对 mp.Process,并发送输入参数,并使用一对 {{ 1}} 的

附带说明,您不需要使用 mp.Queue,因为对“load_data”迭代器的调用总是发生在主进程上。我已将其移至另一个“生产者”进程,该进程将输入放入队列,默认情况下该队列也已自动同步。这允许您拥有一个收集输入的进程,多个处理输入到输出的进程,并让主(父)进程收集输出。如果生成输入的“生产者”受到文件读取速度的 IO 限制(很可能),它也可能在线程中而不是进程中,但在这种情况下,差异可能很小。

我创建了一个自定义“池”的示例,它允许您使用上述“生产者-消费者”方案在每个工人的“生命”结束时返回一些数据。有打印语句来跟踪每个流程中发生的事情,但也请阅读评论以跟踪正在发生的事情以及原因:

Semaphore