- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试在多处理服务器中实现日志记录。根据文档,“不支持从多个进程记录到单个文件”。我创建了一个小程序来检查这个语句:
import logging
import multiprocessing
import os
log = logging.getLogger()
def setup_logger():
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
fileHandler = logging.FileHandler('test.log')
fileHandler.setFormatter(formatter)
log.setLevel(logging.DEBUG)
log.addHandler(fileHandler)
def write_log_entries(identifier, start_event):
start_event.wait()
for i in range(100):
s = ''.join(str(identifier) for k in range(30))
log.info('[{}, {}] --- {}'.format(os.getpid(), identifier, s))
if __name__ == '__main__':
setup_logger()
procs = []
start_event = multiprocessing.Event()
for i in range(100, 300):
p = multiprocessing.Process(target=write_log_entries, args=(i, start_event))
procs.append(p)
for p in procs:
p.start()
start_event.set()
for p in procs:
p.join()
执行完上面的代码后,我希望在“test.log”中看到一团糟,但一切似乎都很好(当然除了时间戳,它们不是按顺序排列的)。
谁能解释为什么多个进程同时写入日志文件时日志条目不重叠?在这种情况下,log.info() 可以被认为是原子的吗?
最佳答案
简短回答:内核锁定对write
的单次调用,所以只要消息很小就没问题,所以它们会在单次write
中刷新,这个 write
成功地一次写完了所有东西。没有普遍保证是这种情况,这就是为什么文档不 promise 这会起作用的原因。
长答案:每次调用 log.info
都会刷新日志输出。这是必要的,否则您将无法在文件中看到最新的日志条目。在 Python/libc 级别,flush 被实现为对 write(2) 系统调用的调用,它被调用以写出文件缓冲区的内容,如果有的话。在您的情况下,缓冲区内容是您的日志消息。因此,Python 或 libc,取决于正在使用的文件,最终会调用操作系统调用,例如:
write(fd, buf, buflen);
...其中 fd
是日志文件的系统级文件描述符,buf
是缓冲写入的内存,buflen
是消息的长度。 (如果你在 Linux 上使用 strace
等工具跟踪你的 Python 进程,你可以看到这些调用。) write
返回成功写入的字符数,内核不会将这些字符与文件同一区域中的其他写入交错。如果文件以 O_APPEND 模式打开,写入甚至可以保证在文件末尾,至少在 Unix 上是这样。所以,如果 buflen
很小,就像正常日志消息一样,一切都很好。但至少有两件事可能会出错。
首先,无法保证所有buflen
都将在一次write
中写出。 write
可以被信号中断,fd
可以指向接受固定大小写入的设备,或者您的日志消息可能大到内核无法接受它在一个 block 中。通常,这不是问题——正确编写的 write
总是作为循环实现的。但在您的情况下,这将是一场灾难,因为对 write
的不同调用会与其他进程交错。
其次,如果您的日志消息足够大以至于无法放入 stdio 缓冲区(8K 左右),那么它将在到达内核之前被分成 block 。在记录回溯或将日志格式化为 XML 等详细格式时,很容易发生这种情况。
关于Python multiprocessing+logging.FileHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12238848/
我正在尝试使用多处理和队列实现生产者-消费者场景;主进程是生产者,两个子进程使用队列中的数据。这在没有任何异常 发生的情况下有效,但问题是我希望能够在工作人员死亡时重新启动他们(kill -9 wor
我试图在一个管理进程下启动一个数据队列服务器(这样它以后可以变成一个服务),虽然数据队列服务器功能在主进程中工作正常,但它在一个进程中不起作用使用 multiprocessing.Process 创建
我的多处理需求非常简单:我从事机器学习工作,有时我需要评估多个数据集中的一个算法,或者一个数据集中的多个算法,等等。我只需要运行一个带有一些参数的函数并获取一个数字。 我不需要 RPC、共享数据,什么
创建进程池或简单地遍历一个进程以创建更多进程之间有任何区别(以任何方式)吗? 这有什么区别?: pool = multiprocessing.Pool(5) pool.apply_async(work
multiprocessing.BoundedSemaphore(3) 与 multiprocessing.Sempahore(3) 有何不同? 我希望 multiprocessing.Bounded
我尝试通过 multiprocessing 包中的 Queue 对 Pipe 的速度进行基准测试。我认为 Pipe 会更快,因为 Queue 在内部使用 Pipe。 奇怪的是,Pipe 在发送大型 n
我有这样一个简单的任务: def worker(queue): while True: try: _ = queue.get_nowait()
我正在尝试编写一个与 multiprocessing.Pool 同时应用函数的应用程序。我希望这个函数成为一个实例方法(所以我可以在不同的子类中以不同的方式定义它)。这似乎是不可能的;正如我在其他地方
在 python 2 中,multiprocessing.dummy.Pool 和 multiprocessing.pool.ThreadPool 之间有什么区别吗?源代码似乎暗示它们是相同的。 最佳
我正在开发一个用于财务目的的模型。我将整个 S&P500 组件放在一个文件夹中,存储了尽可能多的 .hdf 文件。每个 .hdf 文件都有自己的多索引(年-周-分)。 顺序代码示例(非并行化): im
到目前为止,我是这样做的: rets=set(pool.map_async(my_callback, args.hosts).get(60*4)) 如果超时,我会得到一个异常: File "/usr
参见下面的示例和执行结果: #!/usr/bin/env python3.4 from multiprocessing import Pool import time import os def in
我的任务是监听 UDP 数据报,对其进行解码(数据报具有二进制信息),将解码后的信息放入字典中,将字典转储为 json 字符串,然后将 json 字符串发送到远程服务器(ActiveMQ)。 解码和发
我在 macOS 上工作,最近被 Python 3.8 多处理中“fork”到“spawn”的变化所困扰(参见 doc )。下面显示了一个简化的工作示例,其中使用“fork”成功但使用“spawn”失
multiprocessing.Queue 的文档指出从项目入队到其腌制表示刷新到底层管道之间存在一点延迟。显然,您可以将一个项目直接放入管道中(它没有说明其他情况,并且暗示情况就是如此)。 为什么管
我运行了一些测试代码来检查在 Linux 中使用 Pool 和 Process 的性能。我正在使用 Python 2.7。 multiprocessing.Pool 的源代码似乎显示它正在使用 mul
我在 Windows Standard Embedded 7 上运行 python 3.4.3。我有一个继承 multiprocessing.Process 的类。 在类的 run 方法中,我为进程对
我知道multiprocessing.Process类似于 threading.Thread当我子类 multiprocessing.Process 时要创建一个进程,我发现我不必调用 __init_
我有教科书声明说在多处理器系统中不建议禁用中断,并且会花费太多时间。但我不明白这一点,谁能告诉我多处理器系统禁用中断的过程?谢谢 最佳答案 在 x86(和其他架构,AFAIK)上,启用/禁用中断是基于
我正在执行下面的代码并且它工作正常,但它不会产生不同的进程,而是有时所有都在同一个进程中运行,有时 2 个在一个进程中运行。我正在使用 4 cpu 机器。这段代码有什么问题? def f(values
我是一名优秀的程序员,十分优秀!