Pipe

貓 |dd 管道導致沒有 iflag=fullblock 的部分讀取,為什麼截斷為 128KiB?

  • June 16, 2020

考慮這個範例 1MiB 文件:

$ dd if=/dev/zero of=input.img bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00100595 s, 1.0 GB/s

如果我嘗試使用cat它並在dd不使用的情況下將其導入,iflag=fullblock則每個塊的讀取量不能超過 128KiB:

$ cat input.img | dd of=output.img bs=128k count=1
1+0 records in
1+0 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000221117 s, 593 MB/s
$ cat input.img | dd of=output.img bs=129k count=1
0+1 records in
0+1 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000495317 s, 265 MB/s
$ cat input.img | dd of=output.img bs=1M count=1
0+1 records in
0+1 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000437209 s, 300 MB/s

使用 2 個塊計數它甚至會列印一個警告:

$ cat input.img | dd of=output.img bs=129k count=2
dd: warning: partial read (131072 bytes); suggest iflag=fullblock
0+2 records in
0+2 records out
262144 bytes (262 kB, 256 KiB) copied, 0.00107657 s, 243 MB/s

我認為這可能是由於管道緩衝區的大小,但是我在https://www.golinuxhub.com/2018/05/how-to-view-and-increase-default-pipe-size-buffer 之後檢查了它的大小。 html,它似乎設置為 65536 字節:

$ mkfifo /tmp/testfifo
$ python2
>>> fifo_fd = open('/tmp/testfifo', 'rb+')
>>> import fcntl
>>> fcntl.fcntl(fifo_fd, 1032)
65536

(請注意,由於https://bugs.python.org/issue20074,我猜我無法使其與 Python3 一起使用)

主要問題是(純粹的好奇):為什麼讀取被截斷為 128KiB?

(在 Arch Linux、核心 5.4.2、zsh 5.7.1 上測試。)

任何大於PIPE_BUF(現代 UNIX 上為 5k,Linux 上為 4k)的塊大小都不允許在沒有碎片的情況下通過管道。

這意味著,它可能會被拆分,但沒有拆分的授權。

您是否能夠讀取更多內容PIPE_BUF取決於核心的記憶體狀態,該狀態控制核心何時停止寫入端以防止牠吃掉所有核心記憶體。它還取決於讀取端的時序和調度,以及它是否在積累了足夠數量的數據後被喚醒。

順便說一句:dd名為的選項iflag=fullblock是供應商特定的擴展。避免使用它,因為它是非標準的。

另請注意,gcat使用 128k 的寫入塊大小,而 UNIX 版本cat基於mmap()並使用8Mbyte. 因此,如果您確實在遺傳 UNIX 上執行此測試,您可以讀取大於 128k 的塊,

引用自:https://unix.stackexchange.com/questions/556016