【发布时间】:2021-12-14 19:33:10
【问题描述】:
我有一个关于多插座的问题。
我知道我必须将select() 用于多套接字。 select() 等待 fd ...
但是,当我们可以为每个套接字创建一个线程并在每个套接字上分别执行 accept() 时,为什么我们需要使用 select() 呢?这甚至是一个坏主意吗?只是关于“太多的套接字,太多的线程”还是什么??
【问题讨论】:
我有一个关于多插座的问题。
我知道我必须将select() 用于多套接字。 select() 等待 fd ...
但是,当我们可以为每个套接字创建一个线程并在每个套接字上分别执行 accept() 时,为什么我们需要使用 select() 呢?这甚至是一个坏主意吗?只是关于“太多的套接字,太多的线程”还是什么??
【问题讨论】:
确实,您可以通过为每个套接字生成一个线程,然后在每个线程上使用阻塞 I/O 来避免多路复用套接字。
这使您不必处理select()(或poll()等);但是现在您必须改为处理多个线程,这通常会更糟。
在您的特定程序中,线程是否比套接字多路复用更麻烦在很大程度上取决于您的程序试图做什么。例如,如果程序中的线程不需要相互通信/协作或共享任何资源,那么多线程设计可以很好地工作(就像多进程设计一样)。另一方面,如果您的线程都需要访问共享数据结构或其他资源,或者如果它们需要相互交互,那么您将面临一些编程挑战,您需要100% 完美地解决,否则你最终会得到一个“似乎大部分时间都在工作”的程序,但由于不正确/不充分的同步,偶尔会出现死锁、崩溃或给出不正确的结果。这种“元稳定性”现象在有缺陷的多线程程序中比在有缺陷的单线程程序中更为常见/严重,因为每次运行多线程程序的确切执行流程都会有所不同(由于线程相对于彼此)。
除了稳定性和代码正确性问题之外,使用单线程设计还可以避免一些其他多线程特有的问题:
大多数操作系统不能很好地扩展到几十个线程以上。因此,如果您正在考虑每个客户端一个线程,并且希望同时支持数百或数千个客户端,那么您会遇到一些性能问题。
很难控制在阻塞套接字调用中被阻塞的线程。假设用户按下了 Command-Q(或任何适当的等效项),那么现在是时候让您的程序退出了。如果您在阻塞套接字调用中阻塞了一个或多个线程,则没有直接的方法可以做到这一点:
join() 等待它们,因为它们在 I/O 调用内部阻塞,因此可能需要几分钟/几小时/几天他们回应【讨论】: