【问题标题】:Python 3, concurrent.futures.ProcessPoolExecutor and CEF crashes after pool size is reachedPython 3、concurrent.futures.ProcessPoolExecutor 和 CEF 在达到池大小后崩溃
【发布时间】:2021-10-24 03:37:05
【问题描述】:

我在 Win 10 上使用 Python 3.9.6,我正在尝试创建一个小尺寸的 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 倍“无”和 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 的问题,还是两者不能很好地协同工作?我做错了什么?

【问题讨论】:

  • 不管怎样,Windows 中的异常 0x80000003 是一个调试断点。我的猜测是图书馆做了一个断言。
  • 您可以将"debug": True 添加到应用程序设置中,以查看是否显示了其他任何内容。我在代码中没有看到任何明显的内容。

标签: python python-3.x chromium-embedded concurrent.futures


【解决方案1】:

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])

记住:您正在创建新进程,每个进程都有自己的内存空间。因此,使用全局变量绝对没有问题。

更新:如果你想打电话给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])

【讨论】:

  • 哦,我明白了。在阅读了您指出的问题后非常明显:) 我需要为每个实例设置不同的设置和开关,所以我想我必须生成或分叉我自己的进程并且不要使用池。
猜你喜欢
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-06
  • 2012-03-05
  • 1970-01-01
  • 2021-03-05
相关资源
最近更新 更多