我正在将程序转换为多处理,并且需要能够从主进程和子进程登录到单个旋转日志。我正在尝试使用python cookbook Logging to a single file from multiple processes中的第二个示例,该示例启动logger_thread
作为主进程的一部分运行,从子进程添加到的队列中拾取日志消息。该示例效果很好,如果我切换到RotatingFileHandler也可以。
但是,如果我将其更改为在子进程之前启动logger_thread
(以便我也可以从主进程中记录),那么一旦日志轮换,所有后续日志记录都会生成{{1 }}
换句话说,我从第二个例子中改变了这个代码
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
进行测试)然后我遇到了此错误。
我正在使用Windows和python 2.7。 maxBytes
不是stdlib直到python 3.2的一部分,但是我已经复制了Gist的源代码,它说这是安全的。
我不明白为什么首先启动侦听器会有所不同,我也不明白为什么除main之外的任何进程都会尝试访问该文件。
答案 0 :(得分:2)
在子进程之前,不应该启动任何线程。当Python分叉时,线程和IPC状态不会总是被正确复制。
这有几个资源,只是google for fork和threads。有些人声称他们可以做到,但我不清楚它能否正常运作。
首先启动所有流程。
示例附加信息:
Status of mixing multiprocessing and threading in Python
https://stackoverflow.com/a/6079669/4279
在您的情况下,可能是复制的打开文件句柄是问题,但是您仍然应该在线程之前(以及在打开以后想要销毁的任何文件之前)启动子进程。
一些经验法则,由评论中的fantabolous总结:
必须始终在由同一进程创建的任何线程之前启动子进程。
multiprocessing.Pool创建子进程和线程,因此在第一个进程之后不能创建其他进程或池。
创建进程或池时,文件不应该已经打开。 (在某些情况下这是可以的,但不是,例如,如果稍后将删除文件。)
子流程可以创建自己的线程和流程,使用上述相同的规则。
首先启动所有流程是最简单的方法
答案 1 :(得分:2)
因此,您可以简单地创建自己的文件日志处理程序。我还没有看到日志从多处理中出现乱码,所以看起来文件日志轮换是个大问题。只需在您的主程序中执行此操作,您无需更改任何其他日志记录
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)
我愿意猜测每次尝试旋转时锁定都可能会减慢日志记录速度,但是在这种情况下我们需要牺牲性能来保证正确性。