3

I wrote a simple tcp server application, where my fd_set for read includes the connection socket descriptor. The server application, simply sends an ACK, whenever it receives a message. The client application only sends the next message, after it receives an ACK from server.

// timeval == NULL
select(maxfd, &read_set, NULL, NULL, NULL)

When I do this, the performance is about 3K messages/sec. The latency between sending an ack and receiving a response from client is 0.3ms.

// tm.tv_sec=0 and tm.tv_usec=0
select(maxfd, &read_set, NULL, NULL, tm)

But if I do this, the performance goes to 8K messages/sec and latency drops to 0.18ms.

In the latter case, select becomes a poll. Can someone please explain why the latter case performs so much better than the first case?

4

3 回答 3

4

可能的答案

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

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

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

于 2012-12-18T16:23:31.210 回答
1

它不会回答您的问题,但是如果您真的想要良好的性能,并且收到的消息率很高,您可以尝试:

  • 用 O_NONBLOCK 打开
  • 首先尝试阅读
  • 如果读取失败并出现错误代码 EAGAIN 或 EWOULDBLOCK,请使用 timeval == NULL 进行选择
  • 处理数据
于 2012-12-18T16:42:46.377 回答
-2

手册页select(2)

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

添加的重点是我的。如果您担心延迟,您应该查看epoll(4).

于 2012-12-18T16:19:50.087 回答