假设我们有一个基于客户端-服务器的即时消息传递应用程序,而不是p2p。实际的协议并不重要,重要的是服务器架构。可以使用非阻塞套接字将上述服务器编码为以单线程、非并行模式运行,根据定义,它允许我们立即(或立即)有效地执行读写等操作。非阻塞套接字的这一特性允许我们在服务器的核心使用某种选择/轮询功能,几乎不会浪费任何时间在实际的套接字读/写操作上,而是花时间处理所有这些信息。据我所知,如果编码得当,这可能会非常快。但还有第二种方法,那就是积极地多线程,创建一个新的线程(显然是使用某种线程池,因为在某些平台和某些情况下,这个操作可能(非常)慢),并让这些线程并行工作,而主后台线程处理接受()和填充。我已经在网上的不同地方看到过这种方法的解释,所以它显然是存在的。
现在的问题是,如果我们有非阻塞套接字,即时读/写操作,以及一个简单,容易编码的设计,为什么第二个变体还存在?我们试图用第二种设计来克服什么问题,即线程?AFAIK这些通常是用来解决一些缓慢的和可能的阻塞操作,但似乎没有这样的操作存在!
发布于 2011-01-14 02:23:32
我假设您谈论的不是每个客户端有一个线程,因为这样的设计通常是出于完全不同的原因,而是一个线程池,每个线程池处理多个并发客户端。
这种架构与单线程服务器相比的原因只是为了利用多处理器的优势。除了简单的I/O,你还需要做更多的工作,你必须解析消息,做各种工作,甚至可能运行一些更重量级的加密算法。所有这些都需要CPU。如果您想要扩展,利用多个处理器将允许您扩展更多,和/或保持每个客户端的延迟更低。
在多线程环境中,您可能需要更多的锁,这可能会抵消此类设计中的一些收益,但如果操作得当,这可能是一个巨大的胜利--代价是更多的复杂性。
此外,这可能有助于克服操作系统的限制。内核中的I/O路径可能更多地分布在处理器之间。并非所有操作系统都能完全从单线程应用程序线程化IO。回到过去,并不是所有的*nix select()都有很好的替代方案,它通常有1024个filedesciptor限制,一旦你告诉它监控太多的套接字,类似的API就会开始降级。将所有这些客户端分散在多个线程或进程上有助于克服这一限制。
至于线程之间的1:1映射,实现该架构有几个原因:
这里的缺点是它不能扩展,至少不能使用最广泛使用的语言/框架。拥有数千个本机线程会损害性能。尽管有些语言在这里提供了更轻量级的方法,比如Erlang和Go。
https://stackoverflow.com/questions/4682472
复制相似问题