libevent/epoll工作线程数



下面是这个例子。第37行指出,工作线程的数量应该等于cpu内核的数量。为什么会这样?

如果有10k个连接,而我的系统有8个核心,这是否意味着8个工作线程将处理10k个联系?为什么我不应该增加这个数字?

上下文切换

操作系统在线程之间切换上下文需要一点时间。有很多线程,每个线程所做的工作相对较少,这意味着上下文切换时间开始成为应用程序整体运行时的重要组成部分。

例如,操作系统可能需要大约10微秒才能进行上下文切换;如果线程在返回睡眠之前只做了15微秒的工作,那么40%的运行时只是上下文切换!

这是低效的,当你扩大规模时,随着硬件、电源和冷却成本的飙升,这种低效真的开始显现出来。线程很少意味着操作系统不必切换上下文。

因此,在您的情况下,如果您的要求是计算机处理10000个连接,并且您有8个核心,那么效率最佳点将是每个核心1250个连接。

每线程更多客户端

在服务器处理客户端请求的情况下,归根结底是处理每个客户端需要做多少工作。如果这只是少量的工作,那么每个线程都需要处理来自多个客户端的请求,这样应用程序就可以在没有大量线程的情况下处理大量客户端。

在网络服务器中,这意味着要熟悉select()或epoll()系统调用。当调用时,这两个都会使线程进入睡眠状态,直到其中一个提到的文件描述符以某种方式准备就绪。然而,如果没有其他线程在运行时纠缠操作系统,操作系统就不一定需要执行上下文切换;线程可以坐在那里打瞌睡,直到有事情要做(至少这是我对操作系统的理解。每个人,如果我错了,请纠正我!)。当一些数据从客户端出现时,它可以更快地恢复。

当然,这会使线程的源代码变得更加复杂。例如,您不能对来自客户端的数据进行阻塞读取;epoll()告知文件描述符已准备好读取,并不意味着您期望从客户端接收的所有数据都可以立即读取。如果线程由于影响多个客户端的错误而暂停。但这是为了获得尽可能高的效率而付出的代价。

而且,您不一定只希望8个线程与8个内核和10000个连接配合使用。如果你的线程每次处理一个连接时都必须为每个连接做一些事情,那么这是一个需要最小化的开销(通过每个线程有更多的线程和更少的连接)。[select()系统调用就是这样,这就是epoll()被发明的原因。]你必须平衡上下文切换的开销。

对于Linux中的单个进程来说,10000个文件描述符太多了,所以您可能需要几个进程而不是几个线程。还有一个小问题是,无论您的系统有什么响应时间/连接要求,硬件是否从根本上能够支持10000。如果没有,那么您将被迫将应用程序分布在两个或多个服务器上,这可能会变得非常复杂!

确切地了解每个线程要处理多少客户端取决于处理正在做什么,是否涉及硬盘活动等。因此,没有一个单一的答案;不同的应用程序和不同机器上的同一应用程序都不同。调整客户端/线程以达到最高效率是一项非常艰巨的工作。这就是像Solaris上的dtrace、Linux上的ftrace这样的评测工具(尤其是像这样使用时,我在x86硬件上的Linux上使用了很多)等可以提供帮助的地方,因为它们可以让您非常精确地了解线程处理客户端请求时所涉及的运行时。

像谷歌这样的公司当然非常注重效率;他们通了很多电。据我所知,当谷歌选择CPU、硬盘、内存等放入其著名的国产服务器时,他们会根据"每瓦搜索次数"来衡量性能。显然,在你对事情挑剔之前,你必须成为一个相当大的团队,但事情最终会这样。

其他效率

处理TCP网络连接之类的事情本身可能会占用大量的CPU时间,而且很难理解系统中所有CPU运行时的去向。对于网络连接,像智能NIC中的TCP卸载这样的事情可能会带来真正的好处,因为这将CPU从做纠错计算之类的事情的负担中解放出来。

TCP卸载反映了我们在高速大规模实时嵌入式信号处理领域所做的工作。我们使用的(奇怪的)互连需要零CPU时间来运行它们。因此,所有的CPU时间都用于处理数据,而专门的硬件则负责移动数据。这带来了一些相当惊人的效率,因此可以构建一个具有更适中、成本更低、功耗更低的CPU的系统。

语言也会对效率产生根本影响;Ruby、PHP、Perl都很好,但每个最初使用过它们但后来迅速发展起来的人最终都会使用更高效的东西,比如Java/Scala、C++等

你的问题比你想象的还要好!:-P

如果您使用libevent进行联网,它可以在套接字上执行非阻塞I/O一个线程可以做到这一点(使用一个内核),但这会占用CPU。

但是,如果您执行"繁重"的文件I/O,那么内核就没有非阻塞接口。(许多系统根本没有做这件事,其他系统在这个领域有一些半生不熟的东西,但不可移植。–Libevent不使用它。)–如果文件I/O正在扼杀你的程序/测试,那么更高数量的线程将是有意义的!如果使用硬盘,并且i/o调度程序正在重新排序请求以避免磁盘头移动等,这将取决于调度程序考虑了多少请求才能最好地完成其工作。100个挂起的请求可能比8个更好。

为什么不增加线程数

如果完成了非阻塞I/O:所有核心都在使用线程计数=核心计数。更多的线程只意味着更多的线程切换而没有收益。

对于阻塞I/O:您应该增加它!

相关内容

  • 没有找到相关文章

最新更新