【问题标题】:Inconsistent TypeError: cannot serialize '_io.TextIOWrapper' object不一致的类型错误:无法序列化“_io.TextIOWrapper”对象
【发布时间】:2017-05-24 08:37:19
【问题描述】:

我正在 Jupyter 5 上使用 Python 3.6.1。我的目标是测试 portalocker 如何管理同一文件上的并发追加。

为了实现这一点,我创建了一个简单的函数,将单行附加到同一个文件,并使用 multiprocessing.Pool 和 Pool.map() 并行运行该函数。

这是 Jupyter notebook 中的代码。

单元格 1

from time import time
from multiprocessing import Pool
import portalocker


def f(*args):
    while time() < start + 1:
        pass
    with open('portalocker_test.txt', 'a') as f:
        portalocker.lock(f, portalocker.LOCK_EX)
        f.write(f'{time()}\n')

单元格 2

start = time()
with Pool(4) as p:
    p.map(f, range(4))

单元格 3

with open('portalocker_test.txt', 'r') as f:
    for line in f:
        print(line, end='')

如果我在得到预期结果后运行此代码:

单元格 3 外:

1495614277.189394
1495614277.1893928
1495614277.1893911
1495614277.1894028

但如果我再次运行单元 2(不重新启动笔记本),我会得到:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-db9c07d32724> in <module>()
      1 start = time()
      2 with Pool(4) as p:
----> 3     p.map(f, range(4))

/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in map(self, func, iterable, chunksize)
    258         in a list that is returned.
    259         '''
--> 260         return self._map_async(func, iterable, mapstar, chunksize).get()
    261 
    262     def starmap(self, func, iterable, chunksize=None):

/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in get(self, timeout)
    606             return self._value
    607         else:
--> 608             raise self._value
    609 
    610     def _set(self, i, obj):

/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in _handle_tasks(taskqueue, put, outqueue, pool, cache)
    383                         break
    384                     try:
--> 385                         put(task)
    386                     except Exception as e:
    387                         job, ind = task[:2]

/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/connection.py in send(self, obj)
    204         self._check_closed()
    205         self._check_writable()
--> 206         self._send_bytes(_ForkingPickler.dumps(obj))
    207 
    208     def recv_bytes(self, maxlength=None):

/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/reduction.py in dumps(cls, obj, protocol)
     49     def dumps(cls, obj, protocol=None):
     50         buf = io.BytesIO()
---> 51         cls(buf, protocol).dump(obj)
     52         return buf.getbuffer()
     53 

TypeError: cannot serialize '_io.TextIOWrapper' object

如果我在运行单元格 2 之前读取文件,则会引发相同的错误。因此,如果我在运行单元格 2 之前从未打开文件,一切都会正常。如果我之前打开文件,则会收到该错误。 这对我来说很矛盾。到底是怎么回事?如何解决?

另外,使用或不使用portalocker 不会改变这种行为,所以不是portalocker 的问题。我没有在普通 python 上检查它,但我真的很想用 Jupyter 运行它。

【问题讨论】:

  • 为什么你的文件对象和函数同名f?

标签: python-3.x jupyter-notebook


【解决方案1】:

问题是您应该避免为不同的对象使用相同的名称,在您的情况下应该会有所帮助

  • 将函数名称从 f 更改为 function(或与 f 不同的其他名称)

    单元格 1

    from time import time
    from multiprocessing import Pool
    import portalocker
    
    
    def function(*args):
        while time() < start + 1:
            pass
        with open('portalocker_test.txt', 'a') as f:
            portalocker.lock(f, portalocker.LOCK_EX)
            f.write(f'{time()}\n')
    

    单元格 2

    start = time()
    with Pool(4) as p:
        p.map(function, range(4))
    

  • 将使用open 获得的文件对象从f 重命名为file(或与f 不同的其他名称):

    单元格 1

    from time import time
    from multiprocessing import Pool
    import portalocker
    
    
    def f(*args):
        while time() < start + 1:
            pass
        with open('portalocker_test.txt', 'a') as file:
            portalocker.lock(file, portalocker.LOCK_EX)
            file.write(f'{time()}\n')
    

    单元格 3

    with open('portalocker_test.txt', 'r') as file:
        for line in file:
            print(line, end='')
    

或两者兼而有之

【讨论】:

    【解决方案2】:

    我有类似的问题。就我而言,多处理(如:从多处理导入进程)和内存映射文件(导入 mmap)之间存在冲突。删除与内存映射文件相关的代码后,一切正常。

    【讨论】:

      【解决方案3】:

      我也遇到了类似的问题:在我的例子中,一个类持有一个对(非picklable)文件句柄的引用(即成员变量)。一旦我在工作完成后清除它(即设置为无),多处理的一切工作正常。

      我的错误看起来像这样:

      multiprocessing.pool.MaybeEncodingError: Error sending result: '[<backtest.StrategyBacktest object at 0x7efcd7eb6128>]'. Reason: 'TypeError("cannot serialize '_io.TextIOWrapper' object",)'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-05
        • 1970-01-01
        • 2021-10-09
        • 2019-04-29
        • 2022-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多