多处理另一个功能的功能

时间:2018-10-29 09:51:06

标签: python python-3.x multiprocessing shared-memory concurrent.futures

我正在分析仿真的时间序列。基本上,每个时间步长都执行相同的任务。由于时间步长非常多,而且每个时间步长的分析都是独立的,因此我想创建一个可以对另一个功能进行多处理的功能。后者将具有参数,并返回结果。

使用共享字典和libcurrent.futures,我设法编写了这样的代码:

import concurrent.futures as Cfut
def multiprocess_loop_grouped(function, param_list, group_size, Nworkers, *args):
    # function : function that is running in parallel
    # param_list : list of items
    # group_size : size of the groups
    # Nworkers : number of group/items running in the same time
    # **param_fixed : passing parameters

    manager = mlp.Manager()
    dic = manager.dict()
    executor = Cfut.ProcessPoolExecutor(Nworkers)

    futures = [executor.submit(function, param, dic, *args)
           for param in grouper(param_list, group_size)]

    Cfut.wait(futures)
    return [dic[i] for i in sorted(dic.keys())]

通常,我可以这样使用它:

def read_file(files, dictionnary):
    for file in files:
        i = int(file[4:9])
        #print(str(i))
        if 'bz2' in file:
            os.system('bunzip2 ' + file)
            file = file[:-4]
        dictionnary[i] = np.loadtxt(file)
        os.system('bzip2 ' + file)

Map = np.array(multiprocess_loop_grouped(read_file, list_alti, Group_size, N_thread))

或这样:

def autocorr(x):
    result = np.correlate(x, x, mode='full')
    return result[result.size//2:]

def find_lambda_finger(indexes, dic, Deviation):
    for i in indexes :
        #print(str(i))
        # Beach = Deviation[i,:] - np.mean(Deviation[i,:])
        dic[i] = Anls.find_first_max(autocorr(Deviation[i,:]), valmax = True)

args = [Deviation]
Temp = Rescal.multiprocess_loop_grouped(find_lambda_finger, range(Nalti), Group_size, N_thread, *args)

基本上,它正在工作。但是它不能很好地工作。有时会崩溃。有时,它实际上启动了许多与Nworkers相等的python进程,有时在我指定Nworkers = 15时一次只运行2或3个。

例如,我提出的以下主题描述了我遇到的经典错误:Calling matplotlib AFTER multiprocessing sometimes results in error : main thread not in main loop

实现我想要的东西的更多Python方式是什么?如何改善对此功能的控制?如何控制更多正在运行的python进程的数量?

1 个答案:

答案 0 :(得分:1)

Python多处理的基本概念之一是使用队列。当您有一个可以迭代的输入列表,并且不需要由子流程更改时,它会很好地工作。它还使您可以很好地控制所有进程,因为您可以生成所需的数字,因此可以使其空闲或停止。

调试起来也容易得多。显式共享数据通常是一种很难正确设置的方法。

队列可以定义任何东西,因为它们是可迭代的。因此,您可以使用文件路径字符串填充文件以读取文件,使用不可重复的数字进行计算,甚至可以使用图像填充图形。

在您的情况下,布局可能如下所示:

import multiprocessing as mp
import numpy as np
import itertools as it


def worker1(in_queue, out_queue):
    #holds when nothing is available, stops when 'STOP' is seen
    for a in iter(in_queue.get, 'STOP'):
        #do something
        out_queue.put({a: result}) #return your result linked to the input

def worker2(in_queue, out_queue):
    for a in iter(in_queue.get, 'STOP'):
        #do something differently
        out_queue.put({a: result}) //return your result linked to the input

def multiprocess_loop_grouped(function, param_list, group_size, Nworkers, *args):
    # your final result
    result = {}

    in_queue = mp.Queue()
    out_queue = mp.Queue()

    # fill your input
    for a in param_list:
        in_queue.put(a)
    # stop command at end of input
    for n in range(Nworkers):
        in_queue.put('STOP')

    # setup your worker process doing task as specified
    process = [mp.Process(target=function,
               args=(in_queue, out_queue), daemon=True) for x in range(Nworkers)]

    # run processes
    for p in process:
        p.start()

    # wait for processes to finish
    for p in process:
        p.join()

    # collect your results from the calculations
    for a in param_list:
        result.update(out_queue.get())

    return result

temp = multiprocess_loop_grouped(worker1, param_list, group_size, Nworkers, *args)
map = multiprocess_loop_grouped(worker2, param_list, group_size, Nworkers, *args)

当您担心队列的内存不足时,可以使它更具动态性。不需要在进程运行时填充和清空队列。参见示例here

最后一句话:它不是您所要求的Pythonic。但是对于新手来说更容易理解;-)