如何防止 dd 的进度在 Linux 上毫无意义?

ide*_*n42 8 dd

dd在 Linux 上运行命令复制 ISO 时,我得到了一个长时间(几分钟)保持打开状态的进度打印。然后最后一个。

问题似乎是正在使用非常大的缓存,这会混淆dd的输出。

sudo dd bs=4M if=my.iso of=/dev/sdc status=progress
Run Code Online (Sandbox Code Playgroud)

输出(第一行显示很长时间)。

1535115264 bytes (1.5 GB, 1.4 GiB) copied, 1.00065 s, 1.5 GB/s
403+1 records in
403+1 records out
1692844032 bytes (1.7 GB, 1.6 GiB) copied, 561.902 s, 3.0 MB/s
Run Code Online (Sandbox Code Playgroud)

有没有办法防止这种情况发生,以便进度输出有意义?

Sté*_*las 17

从第一行我们可以看出dd在一秒钟内读取和写入了 1.5GB。即使是 SSD 也无法写入那么快。

发生的事情是 /dev/sdc 块设备接受了它(写回),但没有将它发送到磁盘而是缓冲它并开始以磁盘可以接受的速率写入磁盘。类似于 3MiB/s。

系统不能像那样无限期地缓冲数据,在未提交的状态下它只能接受这么多数据。因此,一段时间后(在您的情况下,在写入超过 1.5GB 但经过不到 2 秒后(因为每秒写入进度线)),ddwrite()系统调用将阻塞,直到数据已刷新到磁盘(在此期间它无法写入进度消息)。当它通过时,dd可以发送一些额外丢失的兆字节,并且在不到一秒的时间内发生,因此您只会获得一个额外的进度线。

要查看不同的行为,您可以强制写入同步,除非数据已提交到磁盘,否则不会返回。例如通过使用oflag=syncoflag=dsyncoflag=direct(虽然我不建议这样做)。

  • 扩展“我不建议这样做”:使写入同步是一个坏主意。它可能会降低性能,并且经常在 SSD 上执行此操作会缩短其使用寿命。当内存缓冲区已满时(不完全是发生了什么,但足够接近)进行一次大写比许多小写更有效。 (2认同)

sou*_*edi 5

将文件写入块设备时,请ddoflag=direct. 这使用 O_DIRECT 写入,避免使用您的 RAM 作为回写缓存。请注意,要获得良好的性能,oflag=direct通常需要较大的块大小。

这将避免看到不可能的快速进展,除非你有一个奇怪的设备,它本身有一个非常大的 RAM 缓存

许多设备都有少量缓存。在这种情况下oflag=direct将显示一个现实的进展速度。这更有意义,但它并没有告诉你你想知道的一切:-)。当dd说它完成时,它不保证最后的写入完成。通过使用该选项,您可以确保所有写入都已完成,并检查是否有任何写入错误conv=fsync。这会在最后调用 fsync() 以确保刷新缓存。下面是一个例子:

dd if=my.iso of=/dev/sdc oflag=direct bs=4M status=progress conv=fsync
Run Code Online (Sandbox Code Playgroud)

有些人sync随后运行命令,可以理解的是,他们懒得记住conv=fsync。这不是那么好。 sync不会报告其中一个写入是否失败。

如果设备具有非常大的 RAM 缓存,则必须使用oflag=direct,sync. 但通常我认为oflag=sync这是性能的潜在障碍。您可能希望进一步增加块大小,以降低缓存刷新的频率。当执行非常同步的 IO 并像这样一次读取多个硬件块时,您可能希望使用双缓冲来保持良好的性能,即使用dd下面链接中的第二个命令。

有时您可能还想通过管道从另一个程序(例如gunzip. 在这种情况下,良好的性能还取决于iflag=fullblock并通过另一个dd命令进行管道传输。这里的答案中有一个完整的例子:为什么到 dd 管道的 gunzip 最终会变慢?