我写了一个简单的tcp服务器应用程序,其中我的fd_set for read包含连接套接字描述符。服务器应用程序只要收到消息就会发送一个ACK。客户端应用程序仅在从服务器收到ACK后才发送下一条消息。
// timeval == NULL
select(maxfd, &read_set, NULL, NULL, NULL)
当我这样做时,性能大约是3K消息/秒。发送确认和从客户端接收响应之间的延迟为0.3毫秒。
// tm.tv_sec=0 and tm.tv_usec=0
select(maxfd, &read_set, NULL, NULL, tm)
但如果我这样做,性能将达到8K消息/秒,延迟降至0.18ms。
在后一种情况下,select成为民意调查。有人可以解释为什么后一种情况比第一种情况好得多吗?
答案 0 :(得分:2)
可能的答案
当超时为零时,当没有可用数据时,select()调用立即返回。这允许您忙于等待套接字轮询,主动烧毁CPU周期直到数据到达。
当超时为NULL时,如果没有数据,您的进程将在等待数据可用的WAIT_INTERRUPTIBLE状态下进入休眠状态。这导致至少两个上下文切换的惩罚,一个远离您的进程,一个回到它时数据可用。这样做的好处是您的进程会放弃CPU并允许其他进程运行。
这就像比较spinlocks and semaphores。自旋锁“旋转”CPU等待条件,而信号量产生CPU。自旋锁性能更高,但它们会占用CPU,因此它们只能用于非常短的等待时间。信号量与其他进程更加协作,但由于额外的上下文切换,它们会产生明显的开销。
答案 1 :(得分:0)
它不会回答你的问题,但如果你真的想要表现良好,并且收到的信息率非常高,你可以试试:
答案 2 :(得分:-2)
select(2)
的手册页
增加的重点是我的。如果您担心延迟,请查看超时是之前经过的时间量的上限 select()返回。如果时间结构的两个字段都为零, 然后select()立即返回。 (这对于轮询非常有用。)如果 timeout为NULL(无超时),select()可以无限期阻塞。
epoll(4)
。