我试图理解python日志在以下情况下是如何实现线程安全的: 1.我在主线程中为同一个文件创建不同的处理程序。然后让一个线程登录到它。 2.我从不同的线程中创建指向同一文件的多个处理程序
我在FileHandler的源代码中看到,创建的每个处理程序都有自己的锁,但在我提到的情况下,这是如何工作的? 如果我理解正确,锁的作用域就是FileHandler对象,这意味着如果我创建两个不同的处理程序,它们就不会共享锁,并且可能会遇到竞争条件
所以我的问题是:这个线程如何安全
这是相关代码。请注意,FileHandler类继承StreamHandler,StreamHandler又继承Handler
class StreamHandler(Handler):
"""
A handler class which writes logging records, appropriately formatted,
to a stream. Note that this class does not close the stream, as
sys.stdout or sys.stderr may be used.
"""
terminator = '\n'
def __init__(self, stream=None):
"""
Initialize the handler.
If stream is not specified, sys.stderr is used.
"""
Handler.__init__(self)
if stream is None:
stream = sys.stderr
self.stream = stream
def flush(self):
"""
Flushes the stream.
"""
self.acquire()
try:
if self.stream and hasattr(self.stream, "flush"):
self.stream.flush()
finally:
self.release()
def emit(self, record):
"""
Emit a record.
If a formatter is specified, it is used to format the record.
The record is then written to the stream with a trailing newline. If
exception information is present, it is formatted using
traceback.print_exception and appended to the stream. If the stream
has an 'encoding' attribute, it is used to determine how to do the
output to the stream.
"""
try:
msg = self.format(record)
stream = self.stream
stream.write(msg)
stream.write(self.terminator)
self.flush()
except Exception:
self.handleError(record)
def __repr__(self):
level = getLevelName(self.level)
name = getattr(self.stream, 'name', '')
if name:
name += ' '
return '<%s %s(%s)>' % (self.__class__.__name__, name, level)
class FileHandler(StreamHandler):
"""
A handler class which writes formatted logging records to disk files.
"""
def __init__(self, filename, mode='a', encoding=None, delay=False):
"""
Open the specified file and use it as the stream for logging.
"""
# Issue #27493: add support for Path objects to be passed in
filename = os.fspath(filename)
#keep the absolute path, otherwise derived classes which use this
#may come a cropper when the current directory changes
self.baseFilename = os.path.abspath(filename)
self.mode = mode
self.encoding = encoding
self.delay = delay
if delay:
#We don't open the stream, but we still need to call the
#Handler constructor to set level, formatter, lock etc.
Handler.__init__(self)
self.stream = None
else:
StreamHandler.__init__(self, self._open())
def close(self):
"""
Closes the stream.
"""
self.acquire()
try:
try:
if self.stream:
try:
self.flush()
finally:
stream = self.stream
self.stream = None
if hasattr(stream, "close"):
stream.close()
finally:
# Issue #19523: call unconditionally to
# prevent a handler leak when delay is set
StreamHandler.close(self)
finally:
self.release()
def _open(self):
"""
Open the current base file with the (original) mode and encoding.
Return the resulting stream.
"""
return open(self.baseFilename, self.mode, encoding=self.encoding)
def emit(self, record):
"""
Emit a record.
If the stream was not opened because 'delay' was specified in the
constructor, open it before calling the superclass's emit.
"""
if self.stream is None:
self.stream = self._open()
StreamHandler.emit(self, record)
def __repr__(self):
level = getLevelName(self.level)
return '<%s %s (%s)>' % (self.__class__.__name__, self.baseFilename, level)
我已经实现了线程安全的日志记录。目标是使用线程并行地收集具有不同标记的tweet
以下是我的日志记录实现:
然后在线程中,只需调用Logger类的get_实例方法
我希望这对你有帮助
换句话说,在这两种情况下,处理程序都可以同时打开文件,同时写入文件
这意味着,从某种意义上说,消息可能在文件中“混在一起”(例如,开始写入msg1,然后开始写入msg2,然后继续写入msg1)是不“安全的”
除此之外,我看不出还有什么害处。单独的FileHandler实例不会相互干扰
因此,总而言之,日志文件的内容可能并不完美,但没有其他内容真正破坏
这是一个需要一些逆向工程的好问题
简单的答案是:
FileHandler
在本例中本身不是线程安全的,但不能使用构造函数创建它。而是使用工厂方法,确保线程安全:以及:
请注意这里发生的两件事:
1) 在创建新的
Handler
之前获取锁2) 如果已创建名称记录器,则返回该名称。因此,对于同一个文件,应该只获得一个
FileHandler
实例相关问题 更多 >
编程相关推荐