为什么multiprocessing.Process
的以下start()
方法在针对方法Flask.run()
时不起作用,而在初始化Flask
时引发AttributeError
:
if __name__ == "__main__":
Process(target=app.run,
kwargs=dict(host="0.0.0.0",
port=5002,
ssl_context=('./cert/cert.pem', './cert/cert-key.pem'),
debug=False)
).start()
app.run(host="0.0.0.0", port=5001)
出现以下错误/回溯:
Traceback (most recent call last):
File "projectDir/main.py", line 80, in <module>
Process(target=app.run,
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 284, in _Popen
return Popen(process_obj)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_spawn_posix.py", line 32, in __init__
super().__init__(process_obj)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_fork.py", line 19, in __init__
self._launch(process_obj)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_spawn_posix.py", line 47, in _launch
reduction.dump(process_obj, fp)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/multiprocessing/reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
AttributeError: Can't pickle local object 'Flask.__init__.<locals>.<lambda>'
但是引用函数中的Flask.run()
,并在target=
参数下传递该函数确实有效:
def run_https(**kwargs):
app.run(**kwargs)
if __name__ == "__main__":
Process(target=run_https,
kwargs=dict(host = "0.0.0.0",
port=5002,
ssl_context=('./cert/cert.pem', './cert/cert-key.pem'),
debug=False)
).start()
app.run(host="0.0.0.0", port=5001)
更多上下文:我正试图使用flask_restful
加密与本地SocketServer的通信,但由于证书管理可能需要在所有客户端设备上花费一段时间,我决定在两个进程和两个端口上运行两个Flask()
实例,一个用于http,另一个用于https
提前感谢!
由于子进程的目标是app.run
,Python需要将整个app
对象发送到新的地址空间,方法是用pickle
序列化,然后在新进程的地址空间中反序列化结果。遗憾的是,app
对象无法序列化。原因可能有很多,但归根结底是它有一个或多个无法序列化的属性,因为该属性的性质使得它只在主进程的地址空间中有效。例如,对象的实现可能包括对绝对内存位置或文件描述符的引用,该引用仅在创建对象的地址空间中有效。但是,如果在使用OSfork创建新进程的平台上运行相同的代码,则不会使用pickle
,程序将运行。这是因为新子级的地址空间继承了所有内存(只读/写时复制(和打开文件描述符。参见以下示例:
def worker(f):
print(f.read())
if __name__ == '__main__':
from multiprocessing import Process
with open('test.txt', 'r') as f:
print(type(f))
Process(target=worker, args=(f,)).start()
打印:
<class '_io.TextIOWrapper'>
Traceback (most recent call last):
File "C:Boobootesttest.py", line 8, in <module>
Process(target=worker, args=(f,)).start()
File "C:Program FilesPython38libmultiprocessingprocess.py", line 121, in start
self._popen = self._Popen(self)
File "C:Program FilesPython38libmultiprocessingcontext.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:Program FilesPython38libmultiprocessingcontext.py", line 327, in _Popen
return Popen(process_obj)
File "C:Program FilesPython38libmultiprocessingpopen_spawn_win32.py", line 93, in __init__
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:Program FilesPython38libmultiprocessingspawn.py", line 116, in spawn_main
reduction.dump(process_obj, to_child)
File "C:Program FilesPython38libmultiprocessingreduction.py", line 60, in dump
exitcode = _main(fd, parent_sentinel)
File "C:Program FilesPython38libmultiprocessingspawn.py", line 126, in _main
self = reduction.pickle.load(from_parent)
EOFError: Ran out of input
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_io.TextIOWrapper' object