ProcessPoolExecutor 日志记录无法在 Windows 上记录内部函数,但在 Unix / Mac 上却没有
ProcessPoolExecutor logging fails to log inside function on Windows but not on Unix / Mac
当我 运行 在 Windows 计算机上执行以下脚本时,我没有看到来自 log_pid
函数的任何日志消息,但是当我 运行 在 Unix 上 / Mac。我之前读过 Windows 上的多处理与 Mac 上的不同,但我不清楚我应该进行哪些更改才能使此脚本在 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
策略创建的,其中子进程从父进程中克隆并在父进程分叉时继续执行。
On 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())
...
当我 运行 在 Windows 计算机上执行以下脚本时,我没有看到来自 log_pid
函数的任何日志消息,但是当我 运行 在 Unix 上 / Mac。我之前读过 Windows 上的多处理与 Mac 上的不同,但我不清楚我应该进行哪些更改才能使此脚本在 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
策略创建的,其中子进程从父进程中克隆并在父进程分叉时继续执行。
On 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())
...