为什么使用 Tokio 执行异步网络 IO 的 Rust 项目有数千次写入文件描述符 5?

Why does a Rust project doing async network IO using Tokio have thousands of writes to file descriptor 5?

我正在使用 strace 分析我的系统调用代码。我发现了一些令人惊讶的结果。跟踪显示在进行 200Mb 数据的网络传输时,对文件描述符 5 进行了 47254 次单字节写入。

write(5, "", 1)

这样写是什么意思?什么是 fd 5?它可能来自哪里?有办法查出来吗?

我不太精通Linux基础知识。

ls -lrt /proc/24393/fd

的输出
lrwx------ 1 95th 95th 64 Mar  1 20:56 9 -> 'socket:[97676]'
lr-x------ 1 95th 95th 64 Mar  1 20:56 7 -> /dev/random
lr-x------ 1 95th 95th 64 Mar  1 20:56 6 -> /dev/urandom
l-wx------ 1 95th 95th 64 Mar  1 20:56 5 -> 'pipe:[98345]'
lr-x------ 1 95th 95th 64 Mar  1 20:56 4 -> 'pipe:[98345]'
lrwx------ 1 95th 95th 64 Mar  1 20:56 3 -> 'anon_inode:[eventpoll]'
lrwx------ 1 95th 95th 64 Mar  1 20:56 2 -> /dev/pts/0
lrwx------ 1 95th 95th 64 Mar  1 20:56 1 -> /dev/pts/0
lrwx------ 1 95th 95th 64 Mar  1 20:56 0 -> /dev/pts/0

我检查了那根管子是什么(虽然没什么帮助):

/proc/24393/fd$ lsof | grep 98345
btrs      24393       95th    4r     FIFO               0,11       0t0            98345 pipe
btrs      24393       95th    5w     FIFO               0,11       0t0            98345 pipe
tokio-run 24393 24394 95th    4r     FIFO               0,11       0t0            98345 pipe
tokio-run 24393 24394 95th    5w     FIFO               0,11       0t0            98345 pipe
tokio-run 24393 24395 95th    4r     FIFO               0,11       0t0            98345 pipe
tokio-run 24393 24395 95th    5w     FIFO               0,11       0t0            98345 pipe

mio(作为 tokio 实现的一部分)使用这些写入来唤醒 epoll_wait 系统调用中的工作线程,当它们被文件描述符触发器以外的其他东西唤醒时。由于线程在系统调用的 OS 中被阻塞,这需要某种系统调用来告诉 OS 解除它们的阻塞。这可能是由通道引起的。如果您看到这一点,则表明您有闲置的工作人员。使用此系统调用的替代方法是将这些线程保持在轮询忙等待状态(在系统调用和 CPU 时间上要昂贵得多),或者根本不使用这些线程,直到它们被外部唤醒 I/O (限制你的并发)。我建议您查看这些是否实际上是性能影响或由应用程序其他地方的瓶颈引起的。