如何将线程固定到具有预定内存池对象的核心?(80核Nehalem架构2Tb RAM)

roo*_*-11 14 python multithreading hpc threadpool ipython-parallel

在使用2Tb DRAM的80核(160HT)nehalem架构上运行一些测试后,我遇到了一个小的HPC问题:

当每个线程开始请求关于"错误"套接字上的对象的信息时,具有多于2个套接字的服务器开始停顿很多(延迟),即请求来自正在处理一个套接字上的某些对象的线程以提取信息这实际上是在另一个插槽上的DRAM中.

即使我知道他们正在等待远程套接字返回请求,核心也会100%被利用.

由于大多数代码以异步方式运行,因此重写代码要容易得多,因此我只需解析来自一个套接字上的线程的消息就可以解析其他代码(没有锁定等待).另外我想将每个线程锁定到内存池,因此我可以更新对象而不是浪费时间(~30%)在垃圾收集器上.

因此问题是:

如何在Python中使用预定的内存池对象将线程固定到核心?

更多背景:

当你把ZeroMQ放在中间并且在每个ZMQworker管理的内存池之间传递消息时,Python运行多核没有问题.在ZMQ的8M msg /秒时,对象的内部更新需要比管道填充更长的时间.这一切都在这里描述:http://zguide.zeromq.org/page:all # Chapter-Sockets-and-Patterns

因此,稍微过度简化,我会生成80个ZMQworkerprocesses和1个ZMQrouter,并使用大量对象加载上下文(实际上是5.84亿个对象).从这个"起始点"开始,对象需要进行交互以完成计算.

这是个主意:

  • 如果"对象X"需要与"对象Y"交互并且在python-thread的本地内存池中可用,则应该直接进行交互.
  • 如果"对象Y"在同一个池中不可用,那么我希望它通过ZMQrouter发送消息,让路由器在稍后的某个时间点返回响应.我的架构是非阻塞的,所以在特定的python线程中继续发生的事情只是继续而不等待zmqRouters响应.即使对于同一套接字上但在不同核心上的对象,我宁愿不进行交互,因为我更喜欢干净的消息交换而不是让2个线程操作相同的内存对象.

要做到这一点,我需要知道:

  1. 如何确定给定python进程(线程)运行的套接字.
  2. 如何将特定套接字上的内存池分配给python进程(某些malloc限制或类似内容,以便内存池的总和不会将内存池从一个套接字推送到另一个套接字)
  3. 我没有想到的事情.

但是我无法在python文档中找到关于如何执行此操作的参考资料,并且在google上我必须搜索错误的内容.

更新:

关于"为什么在MPI架构上使用ZeroMQ?"的问题,请阅读主题:Spread vs MPI vs zeromq?由于我工作的应用程序被设计用于即使它在架构测试,其中MPI分布式部署更合适的.

更新2:

关于这个问题:

"如何在Python(3)中将线程固定到具有预定内存池的核心"答案在psutils中:

>>> import psutil
>>> psutil.cpu_count()
4
>>> p = psutil.Process()
>>> p.cpu_affinity()  # get
[0, 1, 2, 3]
>>> p.cpu_affinity([0])  # set; from now on, this process will run on CPU #0 only
>>> p.cpu_affinity()
[0]
>>>
>>> # reset affinity against all CPUs
>>> all_cpus = list(range(psutil.cpu_count()))
>>> p.cpu_affinity(all_cpus)
>>>
Run Code Online (Sandbox Code Playgroud)

工作人员可以与核心挂钩,从而可以有效利用NUMA(查找您的CPU类型以验证它是NUMA架构!)

第二个元素是确定内存池.这可以使用psutils资源库完成:

Jan*_*cke 5

你可能会低估这个问题,没有超级简单的方法来实现你想要的.作为一般准则,您需要在操作系统级别工作,以便按照您希望的方式设置内容.您希望使用所谓的"CPU亲和力"和"内存亲和力",您需要仔细考虑您的系统架构以及您的软件架构才能使事情正确.在真正的HPC中,命名的"亲和力"通常由MPI库处理,例如Open MPI.您可能需要考虑使用一个,并让该MPI库处理您的不同进程.mpi4py包可以提供操作系统,MPI库和Python之间的接口.

您还需要直接获得线程和进程的概念以及操作系统设置.而对于CPU时间调度程序,线程是一个要调度的任务,因此理论上可能具有单独的关联,我只知道整个进程的关联掩码,即一个进程内的所有线程.为了控制内存访问,NUMA(非统一内存访问)是正确的关键字,您可能需要查看http://linuxmanpages.com/man8/numactl.8.php

在任何情况下,您都需要阅读有关亲和主题的文章,并且可能希望开始阅读有关CPU /内存亲和力的Open MPI常见问题解答:http://www.open-mpi.de/faq/? category = tuning #paffinity -defs

如果你想达到你的目标,而无需使用MPI库,看看包装util-linuxschedutilsnumactl你的Linux发行版,以获得有用的命令行工具,比如taskset,你可以从内部的Python,例如呼叫以便为某些相似性掩码进程ID.

本文似乎生动地描述了MPI库如何对您的问题有所帮助:

http://blogs.cisco.com/performance/open-mpi-v1-5-processor-affinity-options/

这个答案描述了如何平分您的硬件架构:https://stackoverflow.com/a/11761943/145400

一般来说,我想知道您申请的机器是否适合该任务,或者您是否正在优化错误的一端.如果您一台计算机进行消息传递并达到内存带宽限制,我不确定ZMQ(通过TCP/IP,对吗?)是否是执行消息传递的正确工具.回到MPI,HPC应用程序消息传递接口......