为什么每多个连接模型被认为比每个连接线程模型更好?

时间:2016-10-08 15:06:52

标签: multithreading asynchronous network-programming scheduler

大多数情况下,您会听到每个多线程连接模型(非阻塞IO)比每个连接线程模型(阻塞io)好得多。并且推理听起来像“每个连接线程的方法创建了太多的线程,并且很多开销与维护这么多线程相关联”。但是没有解释这个开销。

  • 常见的误解是调度开销与所有线程的数量成比例。但事实并非如此,调度开销与可运行线程的数量成比例。因此,在典型的IO绑定应用程序中,大多数线程实际上将在IO上被阻塞,并且只有几个线程可以运行 - 这与“每多个线程连接”模型没有什么不同。
  • 至于上下文切换开销,我希望应该没有区别,因为当数据到达时,内核应该唤醒线程选择器线程或连接线程。
  • 问题可能在于IO系统调用 - 内核可能比阻止IO调用更好地处理kqueue / epoll调用。但是,这听起来似乎不合理,因为在数据到达时选择阻塞线程的O(1)算法应该不是问题。
  • 如果你有许多短暂的连接,你将拥有许多短命的线程。产生新线程是一项昂贵的操作(是吗?)。要解决此问题,您可以创建线程池并仍然使用阻塞I / O.
  • 可能会产生操作系统限制,但可能会使用配置参数更改它们。
  • 在多核系统中,假设不同的会话访问相同的共享数据。如果我们讨论的是每线程连接模型,这可能会导致大量缓存一致性流量,并可能减慢系统速度。但是,如果在给定的时间点只有其中一个线程可以运行,为什么不在单核上设置所有这些线程呢?如果其中多个可运行,则意味着它们应安排在不同的核心上。但是,要在每个多线程连接模型中实现相同的性能,我们需要有多个选择器,它们将被安排在不同的内核上,并将访问相同的共享数据。所以我没有看到缓存视角的差异。
  • 在GC环境中(以Java为例),垃圾收集器应该通过从GC根开始遍历对象图来了解哪些对象可以访问。 GC根包括线程堆栈。因此,GC可以在此图的第一级进行更多工作。但是,对于这两种方法,此图中的活动节点总数应该相同。因此从GC的角度来看没有开销。
  • 我同意的唯一论点是每个线程为其堆栈消耗内存。但即使对于这种情况,如果不使用递归调用,我们可能会限制这些线程的堆栈大小。

你有什么想法?

1 个答案:

答案 0 :(得分:1)

有两个开销:

  1. 堆栈内存。非阻塞IO(以您使用它的任何形式)保存堆栈内存。 IO现在只是一个小型数据结构。
  2. 当负载很高时,减少上下文切换和内核转换。然后,可以使用单个交换机处理多个已完成的IO。
  3. 大多数服务器都没有高负载,因为这样可以减少负载峰值的安全余量。因此,第(2)点主要与人工负荷相关,例如基准(旨在证明一点......)。

    堆栈节省是99%的原因。

    是否需要权衡开发时间和代码复杂性以节省内存取决于您拥有多少连接。在10个连接处,这不是一个问题。在10000个连接处,基于线程的模型变得不可行。

    您在问题中陈述的要点是正确的。

    也许你对“共同的智慧”这一事实感到困惑。是永远使用非阻塞套接字IO?实际上,这种(虚假的)宣传正在网络上随处传播。宣传工作通过反复做出同样简单的陈述而起作用。

相关问题