2012-12-18 55 views
1

我写了一个简单的tcp服务器应用程序,其中我读取的fd_set包含连接套接字描述符。只要收到消息,服务器应用程序就会发送一个ACK。客户端应用程序收到服务器的ACK后才发送下一条消息。linux选择性能场景

// 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.18毫秒。

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

+0

退房[ epoll](http://linux.die.net/man/7/epoll),如果你担心延迟。至于差异,它们是否一致?也许你可以阅读libc/kernel源代码,看看它有什么不同。 –

+0

就像工程中的一切,这是一个折衷。从* system *的角度来看,“select(...,NULL)”在几乎所有情况下都是明显的胜利:它能及时响应;它不占用系统资源。然而在你的情况下,“select(...,tm = 0)”表现更好。为什么? 1),因为你有一个*连续*的网络流量,并且2)响应网络是你所关心的。 – paulsm4

回答

-2

的手册页select(2)

超时是在之前的时间 选择()返回时经过的量的上限。如果timeval结构的两个字段均为零,则 然后select()立即返回。 (这对于轮询非常有用。)如果 超时时间为NULL(无超时),则select()可以无限期地阻止

强调补充是我的。如果你担心延迟,你应该看看epoll(4)

+0

但是大概'read_set' *中的东西已经准备好了,所以这个“can”不能解释它。 –

+0

上限超时应该没关系。只要服务器收到一条消息,select就会返回上述两种情况。 – Jimm

2

可能的答案

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

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

这就像比较spinlocks and semaphores。自旋锁“旋转”CPU等待状态,而信号量产生CPU。 Spinlocks性能更高,但它们使CPU运行起来,因此它们只能用于非常非常短的等待时间。信号量与其他进程更合作,但由于额外的上下文切换,它们会产生明显的开销。

+0

上下文切换的开销是几纳秒。我的66ns。每秒给出8k条消息,这不会加起来 – Jimm

+0

@Jimm你如何测量上下文切换时间?谷歌搜索显示其他人在5-30us的顺序测量上下文切换时间。 –

+0

我使用了https://github.com/tsuna/contextswitch/blob/master/timectxsw.c。你可以分享我其他的链接,我可以尝试那些看到差异 – Jimm

0

它不会回答你的问题,但如果你真的想好性能,并且如果收到的邮件的速度都相当的高,你可以尝试:与O_NONBLOCK

  • 打开
  • 先试着阅读
  • 如果读取错误码EAGAIN或EWOULDBLOCK失败,做选择用的timeval == NULL
  • 过程数据