multiprocessing.pool.MaybeEncodingError: 'TypeError("cannot serialize '_io.BufferedReader' object",)'

tro*_*gne 4 python urllib multiprocessing python-multithreading python-multiprocessing

为什么下面的代码只适用于multiprocessing.dummy,而不适用于 simple 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)
Run Code Online (Sandbox Code Playgroud)

错误 :

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")'
Run Code Online (Sandbox Code Playgroud)

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

Dar*_*aut 6

http.client.HTTPResponse你回来-objecturlopen()有一个_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
Run Code Online (Sandbox Code Playgroud)

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

对此的一般解决方案TypeError是:

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

在你的情况,要求.read()http.client.HTTPResponse将清空并删除缓存,所以功能的响应转换成一些与pickle可以简单地这样做:

def read_buffer(response):
    response.text = response.read()
    return response
Run Code Online (Sandbox Code Playgroud)

例子:

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

在考虑这种方法之前,请确保您确实想要使用多处理而不是多线程。对于像您在这里拥有的 I/O 密集型任务,多线程就足够了,因为大部分时间都花在等待(不需要 CPU 时间)以等待响应。涉及的多处理和 IPC 也引入了大量开销。