python 多处理日志记录:QueueHandler 和 RotatingFileHandler "file being used by another process" 错误
python multiprocessing logging: QueueHandler with RotatingFileHandler "file being used by another process" error
我正在将一个程序转换为多处理,并且需要能够从主进程和子进程记录到单个轮换日志。我正在尝试使用 python 食谱 Logging to a single file from multiple processes 中的第二个示例,它启动 logger_thread
运行 作为主进程的一部分,从队列中获取日志消息子流程添加到。该示例按原样运行良好,如果我切换到 RotatingFileHandler 也可以运行。
但是,如果我将其更改为在子进程之前启动 logger_thread
(这样我也可以从主进程进行日志记录),那么一旦日志轮换,所有后续日志记录都会生成一个回溯 WindowsError: [Error 32] The process cannot access the file because it is being used by another process
.
换句话说,我更改了第二个示例中的代码
workers = []
for i in range(5):
wp = Process(target=worker_process, name='worker %d' % (i + 1), args=(q,))
workers.append(wp)
wp.start()
logging.config.dictConfig(d)
lp = threading.Thread(target=logger_thread, args=(q,))
lp.start()
对此:
logging.config.dictConfig(d)
lp = threading.Thread(target=logger_thread, args=(q,))
lp.start()
workers = []
for i in range(5):
wp = Process(target=worker_process, name='worker %d' % (i + 1), args=(q,))
workers.append(wp)
wp.start()
并将 logging.FileHandler
换成 logging.handlers.RotatingFileHandler
(使用非常小的 maxBytes
进行测试)然后我遇到了这个错误。
我正在使用 Windows 和 python 2.7。 QueueHandler
在 python 3.2 之前不是 stdlib 的一部分,但我已经从 Gist 复制了源代码,它说这样做是安全的。
我不明白为什么首先启动侦听器会有任何不同,也不明白为什么除 main 之外的任何进程都会尝试访问该文件。
你不应该在子进程之前启动 任何 线程。当 Python 分叉时,线程和 IPC 状态将不会始终正确复制。
这方面有几个资源,只有 google 用于 fork 和 threads。有些人声称他们可以做到,但我不清楚它是否可以正常工作。
首先启动所有进程。
附加信息示例:
Status of mixing multiprocessing and threading in Python
在你的情况下,复制的打开文件句柄可能是问题所在,但你仍然应该在你的线程之前启动你的子进程(并且在你打开任何你稍后想要销毁的文件之前)。
一些经验法则,由 fantabolous 从评论中总结:
子进程必须始终在同一进程创建的任何线程之前启动。
multiprocessing.Pool 创建子进程和线程,因此不能在第一个之后创建额外的进程或池。
创建进程或池时文件不应已打开。 (这在某些情况下是可以的,但不是,例如,如果稍后将删除文件。)
子进程可以创建自己的线程和进程,规则同上。
首先启动所有进程是最简单的方法
因此,您可以简单地制作自己的文件日志处理程序。我还没有看到日志因多处理而出现乱码,因此文件日志轮换似乎是个大问题。只需在您的 main 中执行此操作,您不必更改任何其他日志记录
import logging
import logging.handlers
from multiprocessing import RLock
class MultiprocessRotatingFileHandler(logging.handlers.RotatingFileHandler):
def __init__(self, *kargs, **kwargs):
super(MultiprocessRotatingFileHandler, self).__init__(*kargs, **kwargs)
self.lock = RLock()
def shouldRollover(self, record):
with self.lock:
super(MultiprocessRotatingFileHandler, self).shouldRollover(record)
file_log_path = os.path.join('var','log', os.path.basename(__file__) + '.log')
file_log = MultiprocessRotatingFileHandler(file_log_path,
maxBytes=8*1000*1024,
backupCount=5,
delay=True)
logging.basicConfig(level=logging.DEBUG)
logging.addHandler(file_log)
我猜测每次尝试旋转时锁定可能会减慢日志记录速度,但在这种情况下我们需要牺牲性能来换取正确性。
我正在将一个程序转换为多处理,并且需要能够从主进程和子进程记录到单个轮换日志。我正在尝试使用 python 食谱 Logging to a single file from multiple processes 中的第二个示例,它启动 logger_thread
运行 作为主进程的一部分,从队列中获取日志消息子流程添加到。该示例按原样运行良好,如果我切换到 RotatingFileHandler 也可以运行。
但是,如果我将其更改为在子进程之前启动 logger_thread
(这样我也可以从主进程进行日志记录),那么一旦日志轮换,所有后续日志记录都会生成一个回溯 WindowsError: [Error 32] The process cannot access the file because it is being used by another process
.
换句话说,我更改了第二个示例中的代码
workers = []
for i in range(5):
wp = Process(target=worker_process, name='worker %d' % (i + 1), args=(q,))
workers.append(wp)
wp.start()
logging.config.dictConfig(d)
lp = threading.Thread(target=logger_thread, args=(q,))
lp.start()
对此:
logging.config.dictConfig(d)
lp = threading.Thread(target=logger_thread, args=(q,))
lp.start()
workers = []
for i in range(5):
wp = Process(target=worker_process, name='worker %d' % (i + 1), args=(q,))
workers.append(wp)
wp.start()
并将 logging.FileHandler
换成 logging.handlers.RotatingFileHandler
(使用非常小的 maxBytes
进行测试)然后我遇到了这个错误。
我正在使用 Windows 和 python 2.7。 QueueHandler
在 python 3.2 之前不是 stdlib 的一部分,但我已经从 Gist 复制了源代码,它说这样做是安全的。
我不明白为什么首先启动侦听器会有任何不同,也不明白为什么除 main 之外的任何进程都会尝试访问该文件。
你不应该在子进程之前启动 任何 线程。当 Python 分叉时,线程和 IPC 状态将不会始终正确复制。
这方面有几个资源,只有 google 用于 fork 和 threads。有些人声称他们可以做到,但我不清楚它是否可以正常工作。
首先启动所有进程。
附加信息示例:
Status of mixing multiprocessing and threading in Python
在你的情况下,复制的打开文件句柄可能是问题所在,但你仍然应该在你的线程之前启动你的子进程(并且在你打开任何你稍后想要销毁的文件之前)。
一些经验法则,由 fantabolous 从评论中总结:
子进程必须始终在同一进程创建的任何线程之前启动。
multiprocessing.Pool 创建子进程和线程,因此不能在第一个之后创建额外的进程或池。
创建进程或池时文件不应已打开。 (这在某些情况下是可以的,但不是,例如,如果稍后将删除文件。)
子进程可以创建自己的线程和进程,规则同上。
首先启动所有进程是最简单的方法
因此,您可以简单地制作自己的文件日志处理程序。我还没有看到日志因多处理而出现乱码,因此文件日志轮换似乎是个大问题。只需在您的 main 中执行此操作,您不必更改任何其他日志记录
import logging
import logging.handlers
from multiprocessing import RLock
class MultiprocessRotatingFileHandler(logging.handlers.RotatingFileHandler):
def __init__(self, *kargs, **kwargs):
super(MultiprocessRotatingFileHandler, self).__init__(*kargs, **kwargs)
self.lock = RLock()
def shouldRollover(self, record):
with self.lock:
super(MultiprocessRotatingFileHandler, self).shouldRollover(record)
file_log_path = os.path.join('var','log', os.path.basename(__file__) + '.log')
file_log = MultiprocessRotatingFileHandler(file_log_path,
maxBytes=8*1000*1024,
backupCount=5,
delay=True)
logging.basicConfig(level=logging.DEBUG)
logging.addHandler(file_log)
我猜测每次尝试旋转时锁定可能会减慢日志记录速度,但在这种情况下我们需要牺牲性能来换取正确性。