【问题标题】:Select v/s Multithreading in an Multicore Environment在多核环境中选择 v/s 多线程
【发布时间】:2012-01-25 08:43:01
【问题描述】:

我正在编写一个在 3 层上运行的应用程序,每层都有多个实例并形成类似网格的关系。

例如。让我们考虑一个 Matrix 类型的情况:

                     L11 L12

                 L21 L22 L23 L24

                    L31 L32 L33

L11 与 L21,L22,L23,L24 有连接
L21 与 L21,L22,L23,L24 有连接
L21与L11,L12,L31,L32,L33...等有连接

目前我正在使用 UNIX 域套接字与 select 调用进行通信(以确定数据的来源)。选择调用超时如何影响 CPU 使用率??

最好为每个连接生成一个新线程还是坚持选择模型。通常,L1 的水平可扩展性可能约为 5,L2 约为 5,L3 约为 10。

如果传递给 select 的位字段很高,那么 select 系统调用是否会受到惩罚? 如果是多线程应用程序,是使用阻塞系统套接字还是非阻塞?

UNIX-Domain socket 中的 UDP/TCP 有区别吗??

注意:我将使用 12-24 核的系统...可能这就是让我想到为什么不使用单独的线程而不是选择调用的原因..

注意 2:Unix Domain Sockets 中会有缓冲区溢出吗?作为 据我所知,这些都是无损且无序的......

【问题讨论】:

  • 两者都可以。在程序开始时启动 N 个线程,每个物理处理器一个。然后让每个线程以类似选择的方式处理传入连接。主线程将连接分配给子线程进行管理。
  • 您的选项是可能的两种性能最低的 I/O 模型,您要问哪个性能最好?如果您关心性能,为什么还要考虑“选择循环”或“每个连接的线程”?这些是您不关心性能时选择的模型。

标签: c++ performance unix network-programming


【解决方案1】:

我正在编写一个在 3 层上运行的应用程序,每层都有多个实例并形成类似网格的关系。

您的 Matrix 中的所有节点是在同一台主机上运行,​​还是在跨网络的多台主机上运行?

select 调用超时如何影响 CPU 使用率??

只有以明显的方式,每次您的 select() 调用超时,您将不得不围绕您的事件循环进行另一个(否则可能是可以避免的)旋转。因此,例如,总是通过零(或接近零)的超时将是不好的,因为这样您的线程将浪费 CPU 周期忙循环。但是偶尔的超时应该不是问题。我的建议是尽可能纯粹基于事件,并且仅在不可避免的情况下使用超时(例如,因为某某事件必须在特定时间发生,与任何 I/O 流量无关)。

最好为每个连接生成一个新线程还是坚持选择模型。通常,L1 的水平可扩展性可能在 5 左右,L2 将在 5 左右,L3 将在 10 左右。

对于这种规模的操作(数十个连接但不是数百个),select() 可以正常工作。只有当你建立成百上千个连接时,select() 才会开始下降,即使那样你也可以转向 kqueue() 或 epoll() 之类的东西,而不是多线程。

如果传递给 select 的位字段为高,select 系统调用是否会受到惩罚?

我不是 100% 确定您所说的“位字段很高”是什么意思,但如果您的意思是“指定了很多套接字”,那么主要的惩罚是 select() 仅适用于其文件描述符整数值小于 FD_SETSIZE(通常为 1024)——这意味着 select() 一次也不能跟踪超过 FD_SETSIZE 的套接字。 (例外:在 Windows 下,select() 将处理具有任意整数值的套接字,尽管它一次仍不会处理超过 FD_SETSIZE 的套接字)

如果是多线程应用程序,是使用阻塞系统套接字还是非阻塞?

如果是我,即使在多线程应用程序中,我仍然会使用非阻塞 I/O,因为阻塞 I/O 会使某些事情(例如完全关闭应用程序)成为问题。例如,如果您有一个线程在 recv() 中被阻塞,您如何安全地让该线程退出,以便您可以清理任何共享资源?你不能发送信号,因为你不知道哪个线程会接收它,你也不能依赖 recv() 在有限的时间内自然返回。另一方面,如果您的目标线程只在 select() 内阻塞,您可以在它正在执行 select() 的 FD 上向线程发送一个字节,以唤醒它并告诉它离开。

UNIX-Domain socket 中的 UDP/TCP 有区别吗??

Unix-Domain 套接字不使用 UDP 或 TCP(因为它们从不通过网络)。不过,它们确实使用 SOCK_STREAM 和 SOCK_DGRAM,它们的行为(在大多数方面)类似于使用 TCP 和 UDP 套接字连接到 localhost。

注意:我将使用 12-24 核的系统...可能这就是让我想到为什么不使用单独的线程而不是选择调用的原因..

要问自己的问题是,您的应用程序可能是计算密集型还是 I/O 密集型?如果它是计算绑定的(并且计算可以并行化),您可能会受益于将计算分配给多个线程。如果它是 I/O 绑定的,OTOH,多线程将没有任何优势,因为在这种情况下,瓶颈可能是您的网卡(和/或网络本身),而您的千兆以太网插孔仍然存在无论是由一个线程还是多个线程馈送,都将发送最大 1Gb/秒的速度。如果您的所有通信都是与同一主机上的其他进程 OTOH 进行的,那么多线程可能会有一些好处,但我的猜测是这将是最小的,因为看起来您已经将所有内核用于十几个或您拥有的流程。

注意 2:Unix Domain Sockets 中会有缓冲区溢出吗?据我所知,这些都是无损且无序的......

不应该。 SOCK_STREAM 以我的经验,Unix 域套接字的工作方式与 TCP 套接字非常相似。 (我从未使用过 SOCK_DGRAM Unix 域套接字,但我想它们的行为类似于 UDP 套接字,有时甚至会丢弃数据包,例如当接收进程跟不上发送者时)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    • 2012-04-07
    • 1970-01-01
    相关资源
    最近更新 更多