Python 多处理另一个函数的函数

Python 多处理另一个函数的函数,python,python-3.x,multiprocessing,shared-memory,concurrent.futures,Python,Python 3.x,Multiprocessing,Shared Memory,Concurrent.futures,我正在对模拟的时间序列进行分析。基本上,它在每一个时间步都执行相同的任务。由于时间步数非常多,而且对每个时间步的分析都是独立的,所以我想创建一个可以多处理另一个函数的函数。后者将有参数,并返回一个结果 通过使用共享词典和lib concurrent.futures,我成功地编写了以下内容: import concurrent.futures as Cfut def multiprocess_loop_grouped(function, param_list, group_size, Nworke

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

通过使用共享词典和lib concurrent.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)
或者像这样:

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个进程

例如,我得到的一个典型错误在我提出的以下主题中进行了描述:


要实现我的目标,哪种方式更像蟒蛇?如何改进此功能的控制?如何控制更多运行python进程的数量?

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)
当您担心队列内存不足时,可以使其更具动态性。在进程运行时,您需要填充和清空队列。看看这个例子


最后一句话:它并没有像你要求的那样更像蟒蛇。但对于新手来说更容易理解;-)

您希望多处理的功能是否始终相同?或者您是否需要原型
多进程\u循环\u分组
来处理任意函数?流程需要哪些数据?只是时间步?或者其他东西?正如我在主消息末尾的两个使用示例中所看到的,我希望它能够处理任意函数,因为我在分析数据时有多个步骤。通常,我必须对1000组数据运行步骤2,然后对1000组数据运行步骤3,然后对步骤2和步骤3的1000个输出运行步骤4。数据存储在一个numpy数组中,我可以在该数组上进行循环/多处理。例如,我在第二个例子中给出了“偏差”,谢谢你提供这些细节。在开始使用Python多处理功能之前,我看到有两个lib,
concurrent.futures
multiprocessing
,我必须在这两个lib中进行选择。我已经理解了队列的概念,但我猜
并发的
ProcessPoolExecutor
管理了所有这一切,比我使用
多处理
并发编写不同的步骤要好。futures
是一个更容易并行工作的接口。它将较旧的
多处理
多线程
捆绑到一个模块中,并添加了一些功能。因此,这是一个不错的选择。如果您不想关心细节,那么这是一种进行简单多处理的好方法。而且它非常新,所以我没有使用它的经验。我假设
concurrent.futures
与我手动执行的操作完全相同。但在我的代码中,我知道发生了什么。另一种是我通常不喜欢的黑匣子(顺便说一句,我是科学家…)。我从多处理模块开始。