多线程降低了NUMA上的套接字吞吐量

时间:2013-09-24 07:26:27

标签: java linux multithreading sockets numa

我使用Red Had Linux在16核NUMA计算机上对Java程序进行了基准测试。我根据每秒能够接收和发送的数据包(64字节大小)来测量Java DatagramSocket(对于UDP)的吞吐量。该程序由一个套接字和n个正在侦听套接字的线程组成。当数据包到达时,他们会将有效负载复制到byte []数组中,使用该数组创建一个新的DatagramPacket并将其直接发送回它来自的位置。可以把它想象成UDP层上的ping。

  1. 我发现Java DatagramSocket套接字在使用多个线程(即两个或四个)时实现了明显更小的吞吐量。如果我只使用一个线程来监听套接字,我实现了每秒122,000个数据包的吞吐量,而多个线程每秒只能实现65,000个数据包。现在,我知道一个线程可能在NUMA机器的任何核心上执行,并且如果内存必须从一个节点移动到另一个节点,则内存访问会变得昂贵。但是,如果我有两个线程,则只应在“错误”核心上执行一个线程,而另一个线程仍然应该实现非常高的吞吐量。另一个可能的解释是Datagramsocket中的同步问题,但这些只是猜测。有没有人对真正的解释有什么了解?

  2. 我发现在多个端口上多次(并行)执行此程序可以实现更高的总吞吐量。我用一个线程启动程序四次,每个程序在一个单独的端口(5683,5684,5685和5686)上使用套接字。四个程序的总吞吐量为每秒370,000个数据包。总之,在同一端口上使用多个线程会降低吞吐量,而使用多个端口和一个线程会增加吞吐量。这怎么解释?

  3. 系统规格:

    硬件:2个AMD Opteron(TM)处理器6212处理器上的16个内核,分为4个节点,每个节点32 GB RAM。频率:1.4 Ghz,2048 KB缓存。

    node distances:
    node   0   1   2   3
      0:  10  16  16  16
      1:  16  10  16  16
      2:  16  16  10  16
      3:  16  16  16  10
    

    操作系统是红帽企业Linux工作站版本6.4(圣地亚哥),内核版本为2.6.32-358.14.1.el6.x86_64。 Java版"1.7.0_09",Java(TM)SE运行时环境(build 1.7.0_09-b05),Java HotSpot(TM)64位服务器VM(build 23.5-b02, mixed mode)和我使用-XX:+UseNUMA标志。服务器和客户端通过10GB以太网连接。

1 个答案:

答案 0 :(得分:1)

通常,只使用一个线程时效率最高。使东西并行将无形中引入成本。只有当您可以并行执行的额外工作量超过此成本时,才会获得吞吐量的增加。

现在,Amdahl's law说明了吞吐量的理论增益,与您的工作量有多少可以并行化/无法并行化相关。例如,如果只有50%的任务是可并行化的,那么无论您在问题中引入多少线程,都只能使吞吐量增加x2。请注意,您在链接中看到的图表忽略了添加线程的成本。实际上,本机操作系统线程确实增加了相当多的成本,尤其是。当他们中的很多人试图访问共享资源时。

在您的情况下,当您只使用一个套接字时,您的大部分工作都无法并行化。因此,使用单个线程可以提供卓越的性能,并且由于增加了成本,添加线程会使其变得更糟。在第二个实验中,您通过使用多个套接字增加了可以并行化的工作。因此,尽管使用线程增加了一些成本,但您的吞吐量却有所增加。