在流上调用flush()后,如何知道磁盘何时准备就绪?

2024-09-29 21:22:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个名为foo.txt的文件,其中有一行

我想对产生10个新行的每一行应用一个操作。预计输出约为10B行

为了提高速度和IO,foo.txt位于DiskA和bar.txtDiskB上(物理上说是不同的驱动器)

DiskB将成为限制因素。因为有很多行要写,所以我在写入DiskB时添加了一个大的缓冲区

我的问题是:当我在diskB上调用flush()时,文件处理程序的缓冲区会将其刷新到硬盘上。这似乎是一个非阻塞调用,因为命令返回,但我仍然可以看到磁盘正在写入,其忙指示灯为100%。几秒钟后,指示灯返回到0%。python中有没有一种方法可以等待磁盘完成?理想情况下,我希望flush()是一个阻塞调用。我现在看到的唯一解决方案是添加任意sleep(),并希望磁盘准备就绪

下面是一个可视的片段(实际上有点复杂,因为bar.txt不仅仅是一个文件,而是数千个文件,因此IO效率非常低):

with open('bar.txt', 'w', buffering=100 * io.DEFAULT_BUFFER_SIZE) as w:
    with open('foo.txt') as r:
        for line in r:
            # writes each line of foo 10 times in bar.
            for i in range(10):
                w.write(line)
            # w.flush()


Tags: 文件iniotxtfooaswithline
1条回答
网友
1楼 · 发布于 2024-09-29 21:22:42

我认为有几个问题

  • "when the disk is ready"的定义必须非常清楚
  • 您的操作系统、文件系统和配置可能很重要
  • 您的确切用例可能很重要

根据操作系统、文件系统和操作系统/文件系统配置的不同,要知道数据何时写入磁盘将有不同的答案

请注意,以下情况不相同(或可能不相同):

  • 要知道进程何时可以在不阻塞的情况下写入下一个字节
  • 知道其他进程何时可以从文件中读取字节(可能是在刷新之后)
  • 知道操作系统何时将最后一个字节写入磁盘控制器(当刷新所有写缓存时)
  • 知道何时可以在不丢失数据的情况下切断电源/何时数据真正写入磁盘(当磁盘控制器刷新其缓冲区时)

主要的问题是,为什么你必须知道最后一个字节是什么时候写的

如果您的动机是性能,那么也许只有两个线程就足够了:

  • 一种读取和处理线程,它将要写入的数据放入一个队列(threading.Queue),队列中的条目数最大。这意味着,当队列达到一定大小时,读取/处理线程将被阻塞
  • 一种写入线程,它只从队列中读取数据并写入磁盘

如果上述情况是这样的,并且您从未使用过threadingthreading Queue,我可以增强我的回答。告诉我

然而,如果你说,书写/刷新不是/从不阻塞,那么 这没用

为了好玩,您可以实现上述线程,并定期使用第三个线程检查队列的大小,以确定写入是否真的是瓶颈。如果是的话,那么你的FIFO大部分时间都应该(几乎)满了

第一次反馈后的评论:

您正在linux上运行一个SSD驱动器,其中包含要写入的ext4

看起来,但我仍然不确定,一个比问题中更具代表性的例子是,一个脚本只是以不同的数据速率交替写入N个文件

我仍然有这样的印象,增加写缓冲区大小并让操作系统完成其余的工作应该会给您带来性能,而手动干预很难提高性能

不过,禁用磁盘日志记录可能会提高性能

writers = []
writers.append((open("f1", "w", buffering=100 * io.DEFAULT_BUFFER_SIZE), "a")
writers.append((open("f2", "w", buffering=100 * io.DEFAULT_BUFFER_SIZE), "b" * 10000)
writers.append((open("f3", "w", buffering=100 * io.DEFAULT_BUFFER_SIZE), "c" * 100)
...
writers.append((open("f1000", "w", buffering=100 * io.DEFAULT_BUFFER_SIZE), "a" * 200)

for n in range(x):
    # Normally this is where you would read data from a file, 
    # analyse the data and write some data to one or multiple writers
    # as a very approximate simulation I just write to the writers in 
    # data chunks in alternating order

    for writer, data in writers:  
        writer.write(data)

        # this is the question:
        # Can I write lines of the following nature, that will increase 
        # the write rate?
        if some_condition:
            writer.flush()

这个模型会解决你的问题吗?(我知道在现实中,作家的写作速度并不是恒定的,作家写作的顺序也是随机的)

我觉得我错过了什么。 为什么这些潮水会加速任何事情? 这是一个SSD。它没有任何机械延迟等待,磁盘旋转到某个地方。只有在“有足够值得写入的数据”的情况下,缓冲才会写入文件

我还感到困惑的是,你说flush()是非阻塞的

缓冲写入只是将数据放入缓冲区,并在缓冲区已满时调用flush(),这意味着write()也是非阻塞的

如果一切都是非阻塞的,那么您的进程将失去0个编写时间,并且不会有任何需要优化的内容

所以我想,write()和flush()是阻塞调用,但不是以您希望它们阻塞的方式阻塞调用。在操作系统接受数据进行写入之前,它们可能一直处于阻塞状态(这并不意味着数据已经写入) 只要操作系统决定这样做,就会发生对磁盘的真正写入。 由于存在写入缓存,磁盘控制器可能会添加一些其他层的写入缓存/写入重新排序

为了检查这一点,您可以在以下类型的每次写入中添加调试代码

import time
global t_max = 0


...
# this had to be done for every `write` or `flush` 
# or at least for some representative calls of them
t0 = time.time()
bla.write()
t = time.time() - t0
t_max = max(t_max, t)

您可能会有一个t_max,这表明。write是阻塞的 ....

相关问题 更多 >

    热门问题