具有非常大的线程数的多线程

时间:2013-09-30 09:19:45

标签: python multithreading performance simulation

我正在模拟具有大量节点的网状网络。节点在整个网络中的不同主节点之间传递数据。

每个主设备每秒都会接收一次以接收信息,但是从属节点不知道主设备何时启动,因此当他们有信息要发送时,他们每隔5毫秒尝试一次,持续1秒确保他们能找到主人。

在具有1600个节点的常规计算机上运行此操作会导致1600个线程,并且性能非常糟糕。

处理线程的好方法是什么,所以每个节点就好像它在自己的线程上运行一样?

如果它很重要,我正在python 2.7中构建模拟,但如果有意义,我愿意改变其他东西。

4 个答案:

答案 0 :(得分:1)

对我来说,1600个线程听起来很多,但并不过分,因为这是一个模拟。如果这是一个生产应用程序,它可能不具备生产价值。

标准机器在处理1600个线程时应该没有问题。至于操作系统this article可以为您提供一些见解。

当涉及到代码时,Python脚本不是本机应用程序,而是解释的脚本,因此需要更多的CPU资源来执行。

我建议您尝试在C或C ++中实现模拟,这将生成一个应该更有效执行的本机应用程序。

答案 1 :(得分:1)

首先,您是否真的使用默认Python 2.7解释器(CPython)中提供的常规默认Python线程,并且您是Python中的所有代码?如果是这样,你可能实际上并没有使用多个CPU内核,因为CPython具有全局解释器锁(参见https://wiki.python.org/moin/GlobalInterpreterLock)。您可以尝试在Jython下运行代码,只是为了检查性能是否会更好。

您应该重新考虑您的应用程序架构并切换到手动调度事件而不是使用线程,或者尝试使用类似greenlet(https://stackoverflow.com/a/15596277/1488821)之类的东西,但这可能意味着由于缺乏并行性而不太精确的时序。

答案 2 :(得分:1)

不要使用线程。如果坚持使用Python,请让节点逐个执行。如果你这样做的表现没问题,你就不必使用C / C ++。如果每个节点执行的操作很简单,那可能会有效。无论如何,没有理由在Python中使用线程。 Python线程主要用于使阻塞I / O不阻塞程序,而不是用于多CPU内核的利用。

如果您想真正使用并行处理并将节点编写为真正分离并仅使用消息进行交换,则可以使用Erlang(http://www.erlang.org/)。它是一种非常适合执行并行进程并使它们交换消息的函数式语言。 Erlang进程不会映射到OS线程,您可能会创建数千个。但是,Erlang是一种纯函数式语言,如果你从未使用过这样的语言,它可能看起来很奇怪。它也不是很快,因此,像Python一样,除非动作相当简单,否则不可能每5ms处理1600次动作。

最后,如果你没有使用Python或Erlang获得所需的性能,你可以转向C或C ++。但是,仍然不使用1600线程。实际上,只有当线程数量没有显着超过CPU内核数量时,使用线程来获得性能才是合理的。在这种情况下,您可能需要一个反应器模式(具有多个反应器线程)(http://en.wikipedia.org/wiki/Reactor_pattern)。 boost.asio库中有一个很好的reactor模式实现。这里解释:http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/

答案 3 :(得分:0)

这里有一些随意的想法:

我在Java中使用这样的数百个线程做得相当不错;它可以用正确的语言来完成。 (但我没有在Python中尝试过这个。)

在任何语言中,您都可以在一个线程中运行主节点代码;让它连续循环,在每个循环中运行每个主站的代码。但是,你会失去多核心的好处。另一方面,你也会失去多线程的问题。 (你可以说,有4个这样的线程,利用核心,但让多线程头痛回来了。它也会让线程开销也降低,但随后就会出现阻塞......)

我遇到的一个大问题是线程互相阻塞。允许100个线程同时在同一个对象上调用相同的方法而无需等待彼此需要一些思考甚至研究。我发现我的多线程程序最初经常只使用25%的4核CPU,即使在运行时也是如此。这可能是你运行缓慢的一个原因。

不要让您的从属节点重复发送数据。主节点应该响应来自的数据而生效,有某种方式存储它,直到它们活着,某种组合。

拥有比核心更多的线程是值得的。一旦你有两个线程,它们就可以相互阻塞(并且如果它们共享任何数据,它们将会阻塞)。如果您要运行的代码不会阻塞,您希望在自己的线程中运行它,这样它就不会等待阻止解除阻塞并完成的代码。我发现曾经有过一些线程,他们开始像疯了一样繁殖 - 因此我的数百线程程序。即使100个线程在一个位置阻塞,尽管我的所有才华,但还有很多其他线程可以让内核保持忙碌状态!