多处理产生空闲进程,并且不计算任何内容

时间:2019-08-03 15:46:10

标签: python python-3.x windows jupyter-notebook python-multiprocessing

关于多处理库的溢出似乎有很多问题和答案。我已经仔细阅读了所有可以找到的相关内容,却没有找到可以直接解决我问题的内容。

我正在尝试将相同的功能并行应用于多个文件。但是,无论何时我开始处理,计算机都会启动几个python实例,然后什么也不做。根本没有任何计算发生,进程只是闲着

我已经查看了所有关于溢出的类似问题,但似乎没有一个问题涉及到空闲进程。

我在做什么错了?

定义功能(例如,缩写。选中以确保其功能正常)

import pandas as pd
import numpy as np
import glob
import os
#from timeit import default_timer as timer
import talib
from multiprocessing import Process


def example_function(file):

    df=pd.read_csv(file, header = 1)
    stock_name = os.path.basename(file)[:-4]
    macd, macdsignal, macdhist = talib.MACD(df.Close, fastperiod=12, slowperiod=26, signalperiod=9)

    df['macd'] = macdhist*1000
    print(f'stock{stock_name} processed')
    final_macd_report.append(df)

获取我要在其上运行该功能的目录中所有文件的列表

import glob

path = r'C:\Users\josiahh\Desktop\big_test3/*'

files = [f for f in glob.glob(path, recursive=True)]

尝试多处理

import multiprocessing as mp
if __name__ == '__main__':

    p = mp.Pool(processes = 5)
    async_result = p.map_async(example_function, files)
    p.close()
    p.join()
    print("Complete")

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

代码的结构没有错,所以出了问题,您可以从您发布的内容中猜测出来。从简单得多的事情开始,然后逐步将其移至您实际尝试做的事情。您正在导入扩展(第三方)代码山,问题可能出在任何地方。这是一个开始:

def example_function(arg):
    from time import sleep
    msg = "crunching " + str(arg)
    print(msg)
    sleep(arg)
    print("done " + msg)

if __name__ == '__main__':
    import multiprocessing as mp
    p = mp.Pool(processes = 5)
    async_result = p.map_async(example_function, reversed(range(15)))
    print("result", async_result.get())
    p.close()
    p.join()
    print("Complete")

对我来说,在Win10下在64位Python 3.7.4上运行良好。它适合您吗?

请特别注意最后的async_result.get()。这将显示具有15个None值的列表。您永远不会对async_result做任何事情。因此,如果在工作进程中引发任何异常,则该异常很可能会悄然消失。在这种情况下,.get()的结果将(重新)引发主程序中的异常。

还请验证您的files列表实际上是否为空。我们也不能从这里猜出来;-)

编辑

我在async_result.get()之后将map_async()移到了自己的行中,以最大程度地在工作进程中揭示原本沉默的异常。至少也要在代码中添加那么多。

答案 1 :(得分:1)

虽然我什么都没看到错误,但我还是建议一些更改。

通常,Pool中的辅助函数应返回某些内容。该返回值被传送回父进程。我喜欢将其用作状态报告。为了以防万一,在工作进程中捕获异常也是一个好主意。 例如:

def example_function(file):
    status = 'OK'
    try:
        df=pd.read_csv(file, header = 1)
        stock_name = os.path.basename(file)[:-4]
        macd, macdsignal, macdhist = talib.MACD(df.Close, fastperiod=12, slowperiod=26, signalperiod=9)
        df['macd'] = macdhist*1000
        final_macd_report.append(df)
   except:
       status = 'exception caught!'
   return {'filename': file, 'result': status}

(这只是一个简单的示例。您可能希望例如报告完整的异常回溯以帮助进行调试。)

如果工人长时间工作,我希望尽快获得反馈。 因此,我更喜欢使用imap_unordered,尤其是在某些任务比其他任务花费更长的时间的情况下。这将返回一个迭代器,该迭代器以作业完成的顺序生成结果

if __name__ == '__main__':

    with mp.Pool() as p:
        for res in p.imap_unordered(example_function, files):
            print(res)

通过这种方式,您可以明确地证明一个工人完成了工作,结果是什么,是否发生任何问题。

这比从工作人员调用print更好。有了stdout缓冲,并且有多个工作程序继承了相同的输出流,当您实际看到内容时,您无需多言。

编辑:如您所见heremultiprocessing.Pool不适用于交互式解释器,尤其是在ms-windows上。基本上,ms-windows缺少fork系统调用,该调用使类UNIX系统可以复制进程。因此,在ms-windows上,multiprocessing必须尝试模仿fork,这意味着在子进程中导入原始程序文件。这对于像IPython这样的交互式解释器来说效果不佳。可能必须深入研究Jupyter和multiprocessing的内部情况,才能找出问题的确切原因。

针对此问题的解决方法似乎是在单独的模块中定义worker函数,并将其导入IPython中的代码中。

在文档中实际上提到multiprocessing.Pool在交互式解释器中不能很好地工作。请参阅this section末尾的注释。