Python 3:使用多进程队列进行日志记录

5

我最近面临一个挑战,需要将多进程工作集成到我们的软件中。我想让一个主进程生成子进程,并且需要一种方法将日志信息发送回主进程。这主要是因为我们使用的一个模块将警告和错误消息写入到一个日志对象中,而我们希望这些消息出现在运行在主进程中的GUI界面中。

明显的方法是编写一个具有write()方法的小类,该方法将put()到一个队列中,然后在日志流处理程序中使用此类。然后,主进程将从此队列中获取()以将文本发送到GUI。但是这似乎并没有起作用,我不知道为什么。

我编写了一些示例代码来演示这个问题。它使用一个日志对象在一个子进程中写入一个队列,然后主进程尝试从队列中读取,但失败了。有人能帮助我弄清楚这是什么问题吗?

import time, multiprocessing, queue, logging

class FileLikeQueue:
    """A file-like object that writes to a queue"""
    def __init__(self, q):
        self.q = q
    def write(self, t):
        self.q.put(t)
    def flush(self):
        pass


def func(q):
    """This function just writes the time every second for five 
    seconds and then returns. The time is sent to the queue and 
    to a logging object"""

    stream = FileLikeQueue(q)

    log = logging.getLogger()
    infohandler = logging.StreamHandler(stream)
    infohandler.setLevel(logging.INFO)
    infoformatter = logging.Formatter("%(message)s")
    infohandler.setFormatter(infoformatter)
    log.addHandler(infohandler)

    t1 = time.time()
    while time.time() - t1 < 5: #run for five seconds
        log.info('Logging: ' + str(time.time()))
        q.put('Put: %s' % str(time.time()))
        time.sleep(1)



def main():
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=func, args=(q,))
    p.start()

    #read the queue until it is empty
    while True:
        try:
            t = q.get()
        except queue.Empty:
            break
        print(t)


if __name__ == '__main__':
    main()

我希望你能翻译下面的内容:输出应该为:

Logging: 1333629221.01
Put: 1333629221.01
Logging: 1333629222.02
Put: 1333629222.02
Logging: 1333629223.02
Put: 1333629223.02
Logging: 1333629224.02
Put: 1333629224.02
Logging: 1333629225.02
Put: 1333629225.02

但我得到的是:
Put: 1333629221.01
Put: 1333629222.02
Put: 1333629223.02
Put: 1333629224.02
Put: 1333629225.02

所以在func()中的put()操作是有效的,但是日志记录却没有成功。为什么呢?

谢谢。


1
我没有深入研究你的代码,但如果你正在尝试在多进程环境中登录,你可能会发现我不久前写的这个答案很有用。 - Rik Poggi
谢谢你的帮助,Rik。这也很有用。 - Matthew Fournier
1个回答

4
您的问题与日志模块的配置有关:
您需要调用log.setLevel(logging.INFO)。默认的日志级别是WARNING,因此您的日志没有效果。
您确实在处理程序对象上调用了setLevel,但由于被记录的消息被记录器过滤,因此这些消息从未到达处理程序。没有必要在处理程序本身上调用setLevel,因为它默认处理所有消息。

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