multiprocessing.pool.MaybeEncodingError: 'TypeError("cannot serialize '_io.BufferedReader' object",)'
multiprocessing.pool.MaybeEncodingError: 'TypeError("cannot serialize '_io.BufferedReader' object",)'
为什么下面的代码只适用于 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")'
缺少什么才能在没有 "dummy" 的情况下工作?
您从 urlopen()
返回的 http.client.HTTPResponse
-对象附加了一个 _io.BufferedReader
-对象,并且该对象不能被 pickle。
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
将需要对结果进行 pickle(序列化)以将其发送回父进程,这在这里失败了。由于dummy
使用线程而不是进程,所以不会有酸洗,因为同一进程中的线程自然共享内存。
这个TypeError
的一般解决方案是:
- 读出缓冲区并保存内容(如果需要)
- 从您尝试 pickle 的对象中删除对
'_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-bound 任务,就像你在这里拥有的那样,多线程就足够了,因为大部分时间都花在等待响应上(不需要 cpu 时间)。涉及的多处理和 IPC 也会引入大量开销。
为什么下面的代码只适用于 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")'
缺少什么才能在没有 "dummy" 的情况下工作?
您从 urlopen()
返回的 http.client.HTTPResponse
-对象附加了一个 _io.BufferedReader
-对象,并且该对象不能被 pickle。
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
将需要对结果进行 pickle(序列化)以将其发送回父进程,这在这里失败了。由于dummy
使用线程而不是进程,所以不会有酸洗,因为同一进程中的线程自然共享内存。
这个TypeError
的一般解决方案是:
- 读出缓冲区并保存内容(如果需要)
- 从您尝试 pickle 的对象中删除对
'_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-bound 任务,就像你在这里拥有的那样,多线程就足够了,因为大部分时间都花在等待响应上(不需要 cpu 时间)。涉及的多处理和 IPC 也会引入大量开销。