C linux选择性能场景

C linux选择性能场景,c,linux,tcp,C,Linux,Tcp,我编写了一个简单的tcp服务器应用程序,其中用于读取的fd_集包括连接套接字描述符。服务器应用程序只要在收到消息时发送ACK即可。客户端应用程序仅在从服务器收到ACK后发送下一条消息 // timeval == NULL select(maxfd, &read_set, NULL, NULL, NULL) 当我这样做时,性能大约是3K消息/秒。发送ack和从客户端接收响应之间的延迟为0.3ms // tm.tv_sec=0 and tm.tv_usec=0 select(maxfd,

我编写了一个简单的tcp服务器应用程序,其中用于读取的fd_集包括连接套接字描述符。服务器应用程序只要在收到消息时发送ACK即可。客户端应用程序仅在从服务器收到ACK后发送下一条消息

// timeval == NULL
select(maxfd, &read_set, NULL, NULL, NULL)
当我这样做时,性能大约是3K消息/秒。发送ack和从客户端接收响应之间的延迟为0.3ms

// tm.tv_sec=0 and tm.tv_usec=0
select(maxfd, &read_set, NULL, NULL, tm)
但如果我这样做,性能将达到8K消息/秒,延迟将降至0.18ms


在后一种情况下,select将成为轮询。有人能解释一下为什么后一种情况比第一种情况好得多吗

选择(2)的手册页显示

超时是之前经过的时间量的上限 select()返回。如果timeval结构的两个字段都为零, 然后select()立即返回。(这对于轮询很有用。)如果 超时为空(无超时),select()可以无限期阻止


重点是我的。如果您担心延迟,您应该查看。

可能的答案

当超时为零时,如果没有可用数据,select()调用将立即返回。这使您可以忙着等待轮询套接字,在数据到达之前主动消耗CPU周期

当超时为NULL时,如果没有数据,进程将处于等待可中断状态,等待数据可用。这将导致至少两个上下文切换的惩罚,一个离开流程,另一个在数据可用时返回流程。这样做的好处是,您的进程放弃了CPU,并允许其他进程运行


这就像比较。自旋锁“自旋”CPU等待条件,而信号量产生CPU。自旋锁的性能更高,但占用了CPU,因此只能用于非常非常短的等待。信号量与其他进程的协作性更强,但由于额外的上下文切换,它们会产生明显的开销。

这不会回答您的问题,但如果您确实希望获得良好的性能,并且如果接收到的消息率相当高,您可以尝试:

  • 用O_非块打开
  • 首先尝试阅读
  • 如果读取失败,错误代码为EAGAIN或EWOLDBLOCK,请使用timeval==NULL进行选择
  • 过程数据

如果您担心延迟,请查看。至于差异,它们是否一致?也许你可以阅读libc/内核源代码,看看它有什么不同。就像工程中的所有东西一样,这是一种折衷。从系统的角度来看,“select(…,NULL)”几乎在所有情况下都是明显的胜利:它能迅速做出响应;它不会占用系统资源。然而,在您的例子中,“select(…,tm=0)”执行得更好。为什么?1) 因为你有一个连续的网络流量,2)对网络的响应是你所关心的。但是大概
read\u set
中的某些东西已经准备好了,所以这个“can”不能解释它。上限超时应该无关紧要。服务器一收到消息,select就会在上述两种情况下返回。上下文切换的成本只有几纳秒。我的66ns。如果每秒发送8k条消息,则不会添加up@Jimm如何测量上下文切换时间?谷歌搜索显示,其他人测量的上下文切换时间约为5-30秒。你能给我分享一下其他的链接吗?我可以试试看它们的区别。即使是30微秒,有两个上下文切换,即60秒,每次唤醒都会产生额外的60秒。在我的情况下,即使醒来也要大约.1到.18毫秒