Linux poll() 使用 1 个 fd,写入后变慢,读取后变快

Linux poll() 使用 1 个 fd,写入后变慢,读取后变快

问题

我观察到,poll()如果在操作后立即调用,则需要花费几毫秒的时间write(),而如果在操作后立即调用,则仅需要花费几微秒的时间read()

这是使用的代码高手C++ 通信库。

poll()我试图理解为什么一次write()调用与一次调用相比,系统 CPU 调用时间有如此显著的差异read()

系统

[root@主机 ~]#lsb_release -a
LSB 版本::core-4.0-amd64:core-4.0-ia32:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-ia32:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-ia32:printing-4.0-noarch
分销商 ID:RedHatEnterpriseServer
描述:Red Hat Enterprise Linux Server 版本 5.9(Tikanga)
版本:5.9
代号:Tikanga

斯特拉斯

(234,“\4\0S\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\3\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0”...,256)= 256 <0.000048>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.006036>
读取(234,“\4\0S\0\0\0\0\0\1\0\0\0
(234,“\4\0S\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\3\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0”...,256)= 256 <0.000192>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.004996>
读取(234,“\4\20S\0\0\0\0\0\1\0\0\0\200\2\0\0\0\0\3\0\1\0\0\0\0\10\1\0\200\2\0\0” ...,256)= 256 <0.000076>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.000022>
读取(234,“\2\0\0\0\241\352\1\0\0\0\0\0\25\0\0\0\7\0\0\0\242\1\0\0\25\0\0\0\251\1\0\0”...,640)= 640 <0.000337>
(234,“\4\0S\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\3\0\1\0\0\0\0\0\0\0\0\0\0\0\0”...,256)= 256 <0.000096>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.004102>
读取(234,“\4\20S\0\0\0\0\0\1\0\0\0!\1\0\0\0\0\3\0\1\0\0\0\0\10\0\0!\1\0\0” ...,256)= 256 <0.000037>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.000157>
读取(234,“\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\t\0\0\0\10\1\0\0\0\0\0\0\0\0\0\0\0”...,289)= 289 <0.000047>
(234,“\4\0S\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\3\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0”...,256)= 256 <0.000036>
轮询([{fd=234,事件=POLLIN}],1,-1)= 1([{fd=234,事件=POLLIN}])<0.001882>

讨论

尽管 ACE 库可以选择使用它,但迁移到它所带来的好处可能不大,epoll()因为poll()在这种情况下仅使用一个文件描述符进行调用。

当系统加载了 600 多个线程时,此poll()调用将占用相关进程约 98% 的系统调用 CPU 时间。因此,我正在寻找提高效率的方法。然而,问题似乎出在poll()a 之后的调用write(),因为这比 aread()调用后的速度始终慢 100 倍左右。

答案1

一个系统调用与另一个系统调用之间的时间差仅仅是前一个系统调用与下一个系统调用之间的时间差。它只是一个测量目的时间戳,以便用户知道一个系统调用在另一个系统调用之后需要多长时间,并找出应用程序是否挂在某个特定的系统调用上。

然而,我有点困惑为什么这里的读取速度更快。原因很简单,因为写入通常是异步的,但读取往往是直线的,如果我们在不同的文件系统块之间跳跃,磁盘寻道会使其变慢。但看到 revents(请求的事件 - poll() 调用中的第三个参数)表示 POLLIN 表示要读取的数据。也许这可以解释明显的缓慢。尽管如此,我需要整个 strace 才能确定。

答案2

我相信我可能不太相信那些strace告诉我的东西。看着源代码strace我们可以看到,在即将进入系统调用时捕获了当前时间,在系统调用退出时捕获了当前时间。

换句话说,strace 测量的是进入和退出系统调用之间的时间。这意味着它不是测量系统调用消耗了多少 CPU 时间。阻塞调用似乎消耗了应用程序的大部分系统时间 - 但这是挂钟时间,与系统 CPU 的使用量无关。

相关内容