Python 3,concurrent.futures.ProcessPoolExecutor 和 CEF 在达到池大小后崩溃
Python 3, concurrent.futures.ProcessPoolExecutor and CEF crashes after pool size is reached
我在使用 Python 3.9.6 的 Win 10 上,我正在尝试创建一个 concurrent.futures.ProcessPoolExecutor
大小较小的池并向其中添加大量使用 CEF 的任务。
这始终适用于第一个任务,直到达到池大小,之后每个未来都会报告异常
"A process in the process pool was terminated abruptly while the future was running or pending."
只有在我关闭 CEF 时才会出现此问题;当不调用 cef.Shutdown()
时,它不能再被复制。
这是测试代码:
import sys
import concurrent.futures
from cefpython3 import cefpython as cef
def tst():
settings = { "windowless_rendering_enabled": True }
try:
cef.Initialize(settings=settings, switches={})
cef.Shutdown()
except:
print("Unexpected error in tst:", sys.exc_info()[0])
def _main():
futures = []
try:
with concurrent.futures.ProcessPoolExecutor(max_workers=2) as executor:
for i in range(4):
futures.append(executor.submit(tst))
for f in futures:
print(f'{f._state} - {f.exception()}')
except:
print("Unexpected error in main:", sys.exc_info()[0])
if __name__ == '__main__':
_main()
它也是 available online,但我找不到提供 CEF 的在线 python IDE。
预期输出为
FINISHED - None
FINISHED - None
FINISHED - None
但实际输出是
FINISHED - None
FINISHED - None
FINISHED - A process in the process pool was terminated abruptly while the future was running or pending.
将 max_workers 设置为 4 并将范围设置为 6 将遵循该模式,导致 4 次“None”和 2 次错误。
对于每个失败的任务,windows 应用程序日志将列出类似
的错误
Faulting application name: python.exe, version: 3.9.6150.1013, time stamp: 0x60d9eb23
Faulting module name: libcef.dll, version: 3.3359.1774.0, time stamp: 0x5afd9b5a
Exception code: 0x80000003
Fault offset: 0x0000000001e83c58
Faulting application path: ...\Python39\python.exe
Faulting module path: ...\Python39\lib\site-packages\cefpython3\libcef.dll
我做了一个 second version of the test 试图缩小代码中发生崩溃的位置,它似乎就在 cef.Initialize
.
我现在有点迷茫,因为我对 Python 的经验不多,对 CEF 的经验就更少了。是并发包或 CEF 的问题,还是两者不能很好地协同工作?我做错了什么?
CEF 不允许在调用 Shutdown
之后调用 Initialize
。有关详细信息,请参阅 here。
当您的任务多于工作进程时,这些任务将排队等候稍后在工作进程可用时执行。
前 2 个任务 运行 好的,因为为每个任务创建了一个新进程。
第三个任务失败,因为它运行在一个已经被使用的进程中(即:已初始化)。
一个快速的解决方法是添加一个守卫,例如:
initialized = False
def tst():
global initialized
settings = { "windowless_rendering_enabled": True }
try:
if not initialized:
initialized = True
cef.Initialize(settings=settings, switches={})
# you cannot call shutdown now, sorry
#cef.Shutdown()
# do stuff...
except:
print("Unexpected error in tst:", sys.exc_info()[0])
记住:您正在创建新进程,每个进程都有自己的内存space。所以,使用全局变量绝对不会有问题。
更新: 如果你想调用 cef.Shutdown()
你可以这样做(还没有测试过):
import signal
initialized = False
def tst():
global initialized
settings = { "windowless_rendering_enabled": True }
try:
if not initialized:
def signal_handler(_, __):
cef.Shutdown()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
cef.Initialize(settings=settings, switches={})
initialized = True
# do stuff...
except:
print("Unexpected error in tst:", sys.exc_info()[0])
我在使用 Python 3.9.6 的 Win 10 上,我正在尝试创建一个 concurrent.futures.ProcessPoolExecutor
大小较小的池并向其中添加大量使用 CEF 的任务。
这始终适用于第一个任务,直到达到池大小,之后每个未来都会报告异常
"A process in the process pool was terminated abruptly while the future was running or pending."
只有在我关闭 CEF 时才会出现此问题;当不调用 cef.Shutdown()
时,它不能再被复制。
这是测试代码:
import sys
import concurrent.futures
from cefpython3 import cefpython as cef
def tst():
settings = { "windowless_rendering_enabled": True }
try:
cef.Initialize(settings=settings, switches={})
cef.Shutdown()
except:
print("Unexpected error in tst:", sys.exc_info()[0])
def _main():
futures = []
try:
with concurrent.futures.ProcessPoolExecutor(max_workers=2) as executor:
for i in range(4):
futures.append(executor.submit(tst))
for f in futures:
print(f'{f._state} - {f.exception()}')
except:
print("Unexpected error in main:", sys.exc_info()[0])
if __name__ == '__main__':
_main()
它也是 available online,但我找不到提供 CEF 的在线 python IDE。
预期输出为
FINISHED - None
FINISHED - None
FINISHED - None
但实际输出是
FINISHED - None
FINISHED - None
FINISHED - A process in the process pool was terminated abruptly while the future was running or pending.
将 max_workers 设置为 4 并将范围设置为 6 将遵循该模式,导致 4 次“None”和 2 次错误。
对于每个失败的任务,windows 应用程序日志将列出类似
的错误Faulting application name: python.exe, version: 3.9.6150.1013, time stamp: 0x60d9eb23
Faulting module name: libcef.dll, version: 3.3359.1774.0, time stamp: 0x5afd9b5a
Exception code: 0x80000003
Fault offset: 0x0000000001e83c58
Faulting application path: ...\Python39\python.exe
Faulting module path: ...\Python39\lib\site-packages\cefpython3\libcef.dll
我做了一个 second version of the test 试图缩小代码中发生崩溃的位置,它似乎就在 cef.Initialize
.
我现在有点迷茫,因为我对 Python 的经验不多,对 CEF 的经验就更少了。是并发包或 CEF 的问题,还是两者不能很好地协同工作?我做错了什么?
CEF 不允许在调用 Shutdown
之后调用 Initialize
。有关详细信息,请参阅 here。
当您的任务多于工作进程时,这些任务将排队等候稍后在工作进程可用时执行。
前 2 个任务 运行 好的,因为为每个任务创建了一个新进程。
第三个任务失败,因为它运行在一个已经被使用的进程中(即:已初始化)。
一个快速的解决方法是添加一个守卫,例如:
initialized = False
def tst():
global initialized
settings = { "windowless_rendering_enabled": True }
try:
if not initialized:
initialized = True
cef.Initialize(settings=settings, switches={})
# you cannot call shutdown now, sorry
#cef.Shutdown()
# do stuff...
except:
print("Unexpected error in tst:", sys.exc_info()[0])
记住:您正在创建新进程,每个进程都有自己的内存space。所以,使用全局变量绝对不会有问题。
更新: 如果你想调用 cef.Shutdown()
你可以这样做(还没有测试过):
import signal
initialized = False
def tst():
global initialized
settings = { "windowless_rendering_enabled": True }
try:
if not initialized:
def signal_handler(_, __):
cef.Shutdown()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
cef.Initialize(settings=settings, switches={})
initialized = True
# do stuff...
except:
print("Unexpected error in tst:", sys.exc_info()[0])