【问题标题】:multiprocessing for loop with return function that takes more than one arguments带返回函数的多处理 for 循环,该函数接受多个参数
【发布时间】:2019-06-26 00:02:02
【问题描述】:

我知道这个问题被问过多次,但我找不到与我类似的案例。

我有这个功能:

def load_data(list_of_files, INP_DIR, return_featues=False):
    data = []


    # ------- I want to multithread this block------#

    for file_name in tqdm(list_of_files): 

        subject , features = load_subject(INP_DIR,file_name)

        data.append(subject.reset_index())

    # -------------#


    data = pd.concat(data, axis=0, ignore_index=True)

    target = data['label']


    if return_featues: 
        return data,target, features
    else: 
        return data,target 

上述函数使用load_subject,供参考,定义如下:

def load_subject(INP_DIR,file_name):

    subject= pd.read_csv(INP_DIR+ file_name, sep='|')

    < do some processing ...>

    return subject, features

我在 CPU 上有 64 个内核,但我无法使用所有内核。

我用multiprocessing试过这个

train_files= ['p011431.psv', 'p008160.psv', 'p007253.psv', 'p018373.psv', 'p017040.psv',]
from multiprocessing import Pool
if __name__ == '__main__':
    with Pool(processes=64) as pool:  
        pool.map(load_data, train_files)

如您所见,train_files 是文件名列表。

当我运行上面的行时,我得到这个错误:

---------------------------------------------------------------------------
RemoteTraceback                           Traceback (most recent call last)
RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/anaconda3/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/anaconda3/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
TypeError: load_subject() missing 1 required positional argument: 'file_name'
"""

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
<ipython-input-24-96a3ce89ebb8> in <module>()
      2 if __name__ == '__main__':
      3     with Pool(processes=2) as pool:
----> 4         pool.map(load_subject, train_files)  # process data_inputs iterable with pool

/anaconda3/lib/python3.6/multiprocessing/pool.py in map(self, func, iterable, chunksize)
    264         in a list that is returned.
    265         '''
--> 266         return self._map_async(func, iterable, mapstar, chunksize).get()
    267 
    268     def starmap(self, func, iterable, chunksize=None):

/anaconda3/lib/python3.6/multiprocessing/pool.py in get(self, timeout)
    642             return self._value
    643         else:
--> 644             raise self._value
    645 
    646     def _set(self, i, obj):

TypeError: load_subject() missing 1 required positional argument: 'file_name'

更新:

在汤姆的回答之后,我可以找到另一种方法来只传递一个参数。

这里是函数,你会看到我得到的错误:

def load_data(list_of_files):
    data = []


    # ------- I want to multithread this block------#

    for file_name in tqdm(list_of_files): 

        subject , features = load_subject(INP_DIR,file_name)

        data.append(subject.reset_index())

    # -------------#


    data = pd.concat(data, axis=0, ignore_index=True)

    target = data['label']


    return data,target 


def load_subject(file_name):

    subject= pd.read_csv(file_name, sep='|')

    < do some processing ...>

    return subject, features




train_files= ['p011431.psv', 'p008160.psv', 'p007253.psv', 'p018373.psv']

from multiprocessing import Pool
if __name__ == '__main__':
    with Pool(processes=64) as pool:  
        pool.map(load_data, train_files)

当我运行上面的行时,我得到一个新的错误:

---------------------------------------------------------------------------
RemoteTraceback                           Traceback (most recent call last)
RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/anaconda3/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/anaconda3/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
  File "<ipython-input-21-494105028a08>", line 407, in load_data
    subject , features = load_subject(file_name)
  File "<ipython-input-21-494105028a08>", line 170, in load_subject
    subject= pd.read_csv(file_name, sep='|')
  File "/anaconda3/lib/python3.6/site-packages/pandas/io/parsers.py", line 678, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "/anaconda3/lib/python3.6/site-packages/pandas/io/parsers.py", line 440, in _read
    parser = TextFileReader(filepath_or_buffer, **kwds)
  File "/anaconda3/lib/python3.6/site-packages/pandas/io/parsers.py", line 787, in __init__
    self._make_engine(self.engine)
  File "/anaconda3/lib/python3.6/site-packages/pandas/io/parsers.py", line 1014, in _make_engine
    self._engine = CParserWrapper(self.f, **self.options)
  File "/anaconda3/lib/python3.6/site-packages/pandas/io/parsers.py", line 1708, in __init__
    self._reader = parsers.TextReader(src, **kwds)
  File "pandas/_libs/parsers.pyx", line 539, in pandas._libs.parsers.TextReader.__cinit__
  File "pandas/_libs/parsers.pyx", line 737, in pandas._libs.parsers.TextReader._get_header
  File "pandas/_libs/parsers.pyx", line 932, in pandas._libs.parsers.TextReader._tokenize_rows
  File "pandas/_libs/parsers.pyx", line 2112, in pandas._libs.parsers.raise_parser_error
pandas.errors.ParserError: Error tokenizing data. C error: Calling read(nbytes) on source failed. Try engine='python'.
"""

The above exception was the direct cause of the following exception:

ParserError                               Traceback (most recent call last)
<ipython-input-22-d6dcc5840b63> in <module>()
      4 
      5 with Pool(processes=3) as pool:
----> 6     pool.map(load_data, files)

/anaconda3/lib/python3.6/multiprocessing/pool.py in map(self, func, iterable, chunksize)
    264         in a list that is returned.
    265         '''
--> 266         return self._map_async(func, iterable, mapstar, chunksize).get()
    267 
    268     def starmap(self, func, iterable, chunksize=None):

/anaconda3/lib/python3.6/multiprocessing/pool.py in get(self, timeout)
    642             return self._value
    643         else:
--> 644             raise self._value
    645 
    646     def _set(self, i, obj):

ParserError: Error tokenizing data. C error: Calling read(nbytes) on source failed. Try engine='python'.

我在这里缺少什么?我怎样才能使它正常工作?

【问题讨论】:

  • 你没有通过INP_DIR
  • 检查新的更新
  • 你的load_data接受list_of_files ,那么你不能将list_of_files 传递给pool.map。应该是list of list_of_files
  • 在这种情况下,我认为python不会使用所有内核。会吗?
  • 好吧,我猜你是对的。我通过了list of list_of_files,它似乎有效。我怎样才能给你一个赞成票? ;) 谢谢你顺便说一句

标签: python python-3.x multithreading parallel-processing multiprocessing


【解决方案1】:

你的load_data接受list_of_files ,那么你不能将list_of_files 传递给pool.map。应该是list of list_of_files 

得到这样的结果:

with Pool(processes=64) as pool:  
    res = pool.map(load_data, train_files)

【讨论】:

  • 最后一个问题,如何得到输出data?我曾经从load_data 获取数据。我怎样才能把它弄到这里来?
  • @CHAMISoufiane 在多进程池中,你不必使用 res out of with,对不起第一个版本。
  • tbh,即使此代码对我有用且没有错误。我没有看到我的脚本有任何加速或运行时间减少。不幸的是,它似乎不起作用
  • @CHAMISoufiane 你是如何通过 train_files 的?如果你的len(train_files)太小,地图无法帮你加速。
  • 绝对不小。 len(train_files) 等于 5000 元素。我花了 3 个小时才完成这项工作 :( 。我有点沮丧
【解决方案2】:

multiprocessing 的Pool.map() 函数一次只能传递一个参数。我相信在 Python 3 中有一个“正确”的解决方法,但我一直在 Python 2 中使用以下 hack,并且看不出它为什么仍然无法工作。

load_subject 定义一个包装器,它只接受一个参数,定义一个特殊对象用于该参数。

def wrapped_load_subject(param):
    return load_subject(param.inp_dir, param.file_name)

class LoadSubjectParam:
    def __init__(inp_dir, file_name):
        self.inp_dir = inp_dir
        self.file_name = file_name

train_files = []  # Make this a list of LoadSubjectParam objects

with Pool(processes=64) as pool:  
    pool.map(wrapped_load_subject, train_files)

编辑:另外,还有this post

【讨论】:

  • 对不起,汤姆,你的回答很有帮助。但是我没有注意这个错误但是应该是pool.map(load_data, train_files),而不是pool.map(load_data, train_files)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-06
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多