【问题标题】:multiprocessing.pool.MaybeEncodingError: 'TypeError("cannot serialize '_io.BufferedReader' object",)'multiprocessing.pool.MaybeEncodingError: 'TypeError("cannot serialize '_io.BufferedReader' object",)'
【发布时间】:2019-02-17 19:14:14
【问题描述】:

为什么下面的代码只适用于multiprocessing.dummy,而不适用于简单的multiprocessing

import urllib.request
#from multiprocessing.dummy import Pool #this works
from multiprocessing import Pool

urls = ['http://www.python.org', 'http://www.yahoo.com','http://www.scala.org', 'http://www.google.com']

if __name__ == '__main__':
    with Pool(5) as p:
        results = p.map(urllib.request.urlopen, urls)

错误:

Traceback (most recent call last):
  File "urlthreads.py", line 31, in <module>
    results = p.map(urllib.request.urlopen, urls)
  File "C:\Users\patri\Anaconda3\lib\multiprocessing\pool.py", line 268, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "C:\Users\patri\Anaconda3\lib\multiprocessing\pool.py", line 657, in get
    raise self._value
multiprocessing.pool.MaybeEncodingError: Error sending result: '[<http.client.HTTPResponse object at 0x0000016AEF204198>]'. Reason: 'TypeError("cannot serialize '_io.BufferedReader' object")'

缺少什么才能在没有“虚拟”的情况下工作?

【问题讨论】:

    标签: python multiprocessing urllib python-multiprocessing python-multithreading


    【解决方案1】:

    您从urlopen() 返回的http.client.HTTPResponse-object 附加了一个_io.BufferedReader-object,并且该对象不能被腌制。

    pickle.dumps(urllib.request.urlopen('http://www.python.org').fp)
    Traceback (most recent call last):
    ...
        pickle.dumps(urllib.request.urlopen('http://www.python.org').fp)
    TypeError: cannot serialize '_io.BufferedReader' object
    

    multiprocessing.Pool 需要腌制(序列化)结果以将其发送回父进程,但此处失败。由于dummy使用线程而不是进程,所以不会有pickling,因为同一个进程中的线程自然共享它们的内存。

    这个TypeError 的一般解决方案是:

    1. 读出缓冲区并保存内容(如果需要)
    2. 从您尝试腌制的对象中删除对 '_io.BufferedReader' 的引用

    在您的情况下,在 http.client.HTTPResponse 上调用 .read() 将清空并删除缓冲区,因此将响应转换为可腌制内容的函数可以简单地执行以下操作:

    def read_buffer(response):
        response.text = response.read()
        return response
    

    例子:

    r = urllib.request.urlopen('http://www.python.org')
    r = read_buffer(r)
    pickle.dumps(r)
    # Out: b'\x80\x03chttp.client\nHTTPResponse\...
    

    在考虑这种方法之前,请确保您确实想要使用多处理而不是多线程。对于像您在这里拥有的 I/O 绑定任务,多线程就足够了,因为无论如何大部分时间都花在等待响应上(不需要 cpu 时间)。多处理和所涉及的 IPC 也会带来大量开销。

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 2018-07-23
      • 2013-01-07
      • 2020-11-06
      • 2020-12-14
      • 2021-11-27
      • 2020-06-06
      • 1970-01-01
      • 2021-05-21
      相关资源
      最近更新 更多