ProcessPoolExecutor 日志记录无法在 Windows 上登录内部功能,但在 Unix / Mac 上则



当我在Windows计算机上运行以下脚本时,我没有看到来自log_pid函数的任何日志消息,但是当我在Unix/Mac上运行时。我之前读过,与Mac相比,Windows上的多处理是不同的,但是我不清楚应该进行哪些更改才能使此脚本在Windows上运行。我正在运行Python 3.6。

import logging
import sys
from concurrent.futures import ProcessPoolExecutor
import os

def log_pid(x):
logger.info('Executing on process: %s' % os.getpid())

def do_stuff():
logger.info('this is the do stuff function.')
with ProcessPoolExecutor(max_workers=4) as executor:
executor.map(log_pid, range(0, 10))

def main():
logger.info('this is the main function.')
do_stuff()

if __name__ == '__main__':
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.info('Start of script ...')
main()
logger.info('End of script ...')

Unix进程是通过fork策略创建的,其中子进程从父进程克隆,并在父进程分叉的那一刻继续执行。

在Windows上则完全不同:创建一个空白进程并启动一个新的Python解释器。然后,解释器将加载log_pid函数所在的模块并执行它。

这意味着新生成的子进程不会执行__main__部分。因此,不会创建logger对象,并且log_pid函数会相应地崩溃。您看不到错误,因为您忽略了计算结果。尝试按如下方式修改逻辑。

def do_stuff():
logger.info('this is the do stuff function.')
with ProcessPoolExecutor(max_workers=4) as executor:
iterator = executor.map(log_pid, range(0, 10))
list(iterator)  # collect the results in a list

这个问题将变得明显。

Traceback (most recent call last):
File "C:Program Files (x86)Python36-32libconcurrentfuturesprocess.py", line 175, in _process_worker
r = call_item.fn(*call_item.args, **call_item.kwargs)
File "C:Program Files (x86)Python36-32libconcurrentfuturesprocess.py", line 153, in _process_chunk
return [fn(*args) for args in chunk]
File "C:Program Files (x86)Python36-32libconcurrentfuturesprocess.py", line 153, in <listcomp>
return [fn(*args) for args in chunk]
File "C:UserscafamaDesktoppool.py", line 8, in log_pid
logger.info('Executing on process: %s' % os.getpid())
NameError: name 'logger' is not defined

在处理进程池(无论是concurrent.futures还是multiprocessing进程池)时,请始终收集计算结果,以避免静默错误引起混淆。

要解决此问题,只需将logger创建移动到模块的顶层,一切将在所有平台上运行。

import logging
import sys
from concurrent.futures import ProcessPoolExecutor
import os
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)   
def log_pid(x):
logger.info('Executing on process: %s' % os.getpid())
...

相关内容

  • 没有找到相关文章

最新更新