ProcessPoolExecutor在Windows上无法记录函数内部的日志,但在Unix / Mac上可以

13
当我在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 ...')
1个回答

18

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-32\lib\concurrent\futures\process.py", line 175, in _process_worker
    r = call_item.fn(*call_item.args, **call_item.kwargs)
  File "C:\Program Files (x86)\Python36-32\lib\concurrent\futures\process.py", line 153, in _process_chunk
    return [fn(*args) for args in chunk]
  File "C:\Program Files (x86)\Python36-32\lib\concurrent\futures\process.py", line 153, in <listcomp>
    return [fn(*args) for args in chunk]
  File "C:\Users\cafama\Desktop\pool.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())

...

这在Linux上对我有效,但不幸的是,在Windows上不行 :( - codeananda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接