Могу ли я использовать многопроцессорную обработку.Пул в методе класса?

Я пытаюсь использовать multiprocessing в моем коде для лучшей производительности.

тем не менее, я получил ошибку следующим образом:

Traceback (most recent call last):
  File "D:EpubBuilderTinyEpub.py", line 49, in <module>
    e.epub2txt()
  File "D:EpubBuilderTinyEpub.py", line 43, in epub2txt
    tempread = self.get_text()
  File "D:EpubBuilderTinyEpub.py", line 29, in get_text
    txtlist = pool.map(self.char2text,charlist)
  File "C:Python34libmultiprocessingpool.py", line 260, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "C:Python34libmultiprocessingpool.py", line 599, in get
    raise self._value
  File "C:Python34libmultiprocessingpool.py", line 383, in _handle_tasks
    put(task)
  File "C:Python34libmultiprocessingconnection.py", line 206, in send
    self._send_bytes(ForkingPickler.dumps(obj))
  File "C:Python34libmultiprocessingreduction.py", line 50, in dumps
    cls(buf, protocol).dump(obj)
TypeError: cannot serialize '_io.BufferedReader' object

я попробовал это по-другому и получил эту ошибку:

TypeError: cannot serialize '_io.TextIOWrapper' object

мой код выглядит так:

from multiprocessing import Pool
class Book(object):
    def __init__(self, arg):
        self.namelist = arg
    def format_char(self,char):
        char = char + "a"
        return char
    def format_book(self):
        self.tempread = ""
        charlist = [f.read() for f in self.namelist] #list of char
        with Pool() as pool:
            txtlist = pool.map(self.format_char,charlist)
        self.tempread = "".join(txtlist)
        return self.tempread

if __name__ == '__main__':
    import os
    b = Book([open(f) for f in os.listdir()])
    t = b.format_book()
    print(t)

Я думаю, что ошибка возникает из-за не используя Pool в главном функции.

верно ли мое предположение? И как я могу изменить свой код, чтобы исправить ошибку?

1 ответов


проблема в том, что у вас есть непиклируемая переменная экземпляра (namelist) в Book экземпляра. Потому что ты звонишь pool.map в методе экземпляра, и вы работаете в Windows, весь экземпляр должен быть picklable для того, чтобы он был передан дочернему процессу. Book.namelist - открытый файловый объект (_io.BufferedReader), который нельзя мариновать. Вы можете исправить это несколькими способами. Основываясь на примере кода, похоже, вы можете просто сделать format_char топ-уровня функция:

def format_char(char):
    char = char + "a"
    return char


class Book(object):
    def __init__(self, arg):
        self.namelist = arg

    def format_book(self):
        self.tempread = ""
        charlist = [f.read() for f in self.namelist] #list of char
        with Pool() as pool:
            txtlist = pool.map(format_char,charlist)
        self.tempread = "".join(txtlist)
        return self.tempread

однако, если на самом деле, вам нужно format_char чтобы быть методом экземпляра, вы можете использовать __getstate__/__setstate__ сделать Book picklable, путем извлекать namelist аргумент от экземпляра перед его маринованием:

class Book(object):
    def __init__(self, arg):
        self.namelist = arg

    def __getstate__(self):
        """ This is called before pickling. """
        state = self.__dict__.copy()
        del state['namelist']
        return state

    def __setstate__(self, state):
        """ This is called while unpickling. """
        self.__dict__.update(state)

    def format_char(self,char):
        char = char + "a"

    def format_book(self):
        self.tempread = ""
        charlist = [f.read() for f in self.namelist] #list of char
        with Pool() as pool:
            txtlist = pool.map(self.format_char,charlist)
        self.tempread = "".join(txtlist)
        return self.tempread

это было бы нормально, пока вам не нужно получить доступ namelist в дочернем процессе.