Kra*_* Li 23 python python-multiprocessing
有人告诉我,日志记录不能用于多处理.在多处理混淆日志的情况下,您必须执行并发控制.
但我做了一些测试,似乎在使用多处理登录时没有问题
import time
import logging
from multiprocessing import Process, current_process, pool
# setup log
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='/tmp/test.log',
filemode='w')
def func(the_time, logger):
proc = current_process()
while True:
if time.time() >= the_time:
logger.info('proc name %s id %s' % (proc.name, proc.pid))
return
if __name__ == '__main__':
the_time = time.time() + 5
for x in xrange(1, 10):
proc = Process(target=func, name=x, args=(the_time, logger))
proc.start()
Run Code Online (Sandbox Code Playgroud)
正如您从代码中看到的那样.
我故意让子进程在同一时刻(开始后5s)写日志以增加冲突的可能性.但是根本没有冲突.
所以我的问题是我们可以在多处理中使用日志记录吗?为什么这么多帖子说我们不能?
mat*_*ino 20
从多个进程写入单个文件是不安全的.
虽然记录是线程安全的,并登录到从多个线程在单个进程中一个单独的文件支持,记录从多个进程的单个文件不支持,因为能够连续访问多个单个文件没有标准的方法Python中的进程.
一种可能的解决方案是让每个进程写入自己的文件.您可以通过编写自己的处理程序来实现此目的,该处理程序将进程pid添加到文件的末尾:
import logging.handlers
import os
class PIDFileHandler(logging.handlers.WatchedFileHandler):
def __init__(self, filename, mode='a', encoding=None, delay=0):
filename = self._append_pid_to_filename(filename)
super(PIDFileHandler, self).__init__(filename, mode, encoding, delay)
def _append_pid_to_filename(self, filename):
pid = os.getpid()
path, extension = os.path.splitext(filename)
return '{0}-{1}{2}'.format(path, pid, extension)
Run Code Online (Sandbox Code Playgroud)
然后你只需要打电话addHandler
:
logger = logging.getLogger('foo')
fh = PIDFileHandler('bar.log')
logger.addHandler(fh)
Run Code Online (Sandbox Code Playgroud)
han*_*ast 17
正如Matino正确解释的那样:登录多处理设置并不安全,因为多个进程(对现有的其他进程不了解)正在写入同一个文件,可能相互干预.
现在发生的是每个进程都拥有一个打开的文件句柄并对该文件进行"追加写入".问题是在什么情况下追加写入是"原子的"(也就是说,不能被例如写入同一文件并混合其输出的另一个进程中断).这个问题适用于每种编程语言,因为最终他们会对内核进行系统调用.这个答案回答了在哪种情况下共享日志文件是可以的.
它归结为检查管道缓冲区大小,在linux上定义的/usr/include/linux/limits.h
是4096字节.对于其他操作系统,您可以在这里找到一个很好
这意味着:如果您的日志行小于4'096字节(如果在Linux上),则附加是安全的,如果磁盘是直接连接的(即中间没有网络).但是有关详细信息,请查看我的答案中的第一个链接.要测试这个,您可以logger.info('proc name %s id %s %s' % (proc.name, proc.pid, str(proc.name)*5000))
使用不同的长度.以5000为例,我已经混入了日志行/tmp/test.log
.
在这个问题中已经有很多解决方案,所以我不会在这里添加自己的解决方案.
更新:Flask和多处理
如果由uwsgi或nginx托管,那么像flask这样的Web框架将在多个worker中运行.在这种情况下,多个进程可以写入一个日志文件.会有问题吗?
烧瓶中的错误处理是通过stdout/stderr完成的,然后由网络服务器(uwsgi,nginx等)完成,这需要注意以正确的方式写入日志(参见例如[此烧瓶+ nginx示例])(http://flaviusim.com/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/),可能还添加了流程信息,因此您可以将错误行与流程相关联.来自烧瓶文件:
默认情况下,从Flask 0.11开始,错误会自动记录到您的Web服务器日志中.但警告不是.
因此,如果您使用warn
并且消息超出管道缓冲区大小,您仍然会遇到此问题的混合日志文件.
归档时间: |
|
查看次数: |
5930 次 |
最近记录: |