【问题标题】:Multithreading With Very Large Number of Threads具有大量线程的多线程
【发布时间】:2013-10-06 02:25:05
【问题描述】:

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

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

在具有 1600 个节点的普通计算机上运行此程序会导致 1600 个线程,并且性能极差。

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

如果这很重要,我会在 python 2.7 中构建模拟,但如果有意义的话,我愿意更改为其他东西。

【问题讨论】:

  • 您应该考虑实现某种(线程)队列或至少一个调度程序来管理信息流。但是,如果不知道您想要完成什么,就很难说清楚。
  • 运行 1600 个线程当然会导致普通计算机性能不佳。您可能需要考虑高性能计算机,或者您可以尝试利用 GPU 来获得更多计算能力。 GPU 非常适合多线程。
  • @justhalf 当然会很糟糕。每个线程每秒只活动几毫秒,其余时间都在休眠,所以我认为问题不在于 CPU 资源,而在于核心数量或仅仅是存在那么多线程和上下文切换它们要求。我什至应该说 10,000 而不是 1600。我正在寻找一个很好的解决方案来近似这些节点并行运行以最大化我可以运行的节点数量。我认为迁移到 GPU 并没有真正的帮助。
  • “逼近这些节点”是什么意思?
  • 近似它们的全部并行特征。在常规 CPU 上运行让我无法只为每个节点提供自己的线程并假设它们将齐头并进。例如,我可以有一个(或几个)控制线程,当其中一个节点有信息要发送时,它会启动较小的线程,但大多数时候每个节点都没有一个线程。

标签: python multithreading performance simulation


【解决方案1】:

不要为此使用线程。如果坚持 Python,让节点一个一个地执行它们的动作。如果这样做的性能还可以,则不必使用 C/C++。如果每个节点执行的操作都很简单,那可能会奏效。无论如何,根本没有理由在 Python 中使用线程。 Python 线程主要用于使阻塞 I/O 不会阻塞您的程序,而不是用于多个 CPU 内核的利用。

如果您想真正使用并行处理并编写您的节点,就好像它们真的是分开的并且只使用消息交换,您可以使用 Erlang (http://www.erlang.org/)。它是一种非常适合执行并行进程并让它们交换消息的函数式语言。 Erlang 进程不映射到操作系统线程,您可能会创建数以千计的线程。但是,Erlang 是一种纯粹的函数式语言,如果您从未使用过此类语言,您可能会觉得非常奇怪。而且它也不是很快,所以像 Python 一样,不可能每 5 毫秒处理 1600 个动作,除非动作相当简单。

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

【讨论】:

  • 我这里的目标不是增加多线程的吞吐量,而是模拟节点间的通信。每个节点上的处理很少。我来看看 erlang 看看它的样子。
【解决方案2】:

这里有一些随机的想法:

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

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

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

不要让您的从节点重复发送数据。主节点应该响应进入的数据而激活,有某种方式存储它直到它们激活,某种组合。

拥有比内核更多的线程确实值得。一旦你有两个线程,它们就可以互相阻塞(如果它们共享任何数据,它们也会阻塞)。如果您要运行不会阻塞的代码,则希望在其自己的线程中运行它,这样它就不会等待确实阻塞的代码解除阻塞并完成。我发现一旦我有了几个线程,它们就开始疯狂地繁殖——因此我的数百个线程程序。尽管我的才华横溢,即使有 100 个线程在一个地方阻塞,还有很多其他线程可以让内核保持忙碌!

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我正在使用 Canopy 附带的 python(经过深思熟虑)。我认为这是常规的 CPython。
    • 通过谷歌搜索,看起来确实如此。但正如其他人也建议的那样,您的问题最好通过使用不同的应用程序架构来解决。
    • 我将架构切换为使用 gevents,每个节点都在自己的 greenlet 上运行。对于我的应用程序,这实际上工作得很好,因为我不需要实际的并行功能,并发性就足够了。 (基本上,Master 的 greenlet 只是为 Master 主动接收连接设置一个标志,Slave 直接在 Master 上查询该值。)谢谢你的想法。
    【解决方案4】:

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

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

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

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

    【讨论】:

    • C# 可能也值得一看。它可以正确地执行线程(与 Python 不同),并且对于那些习惯了 Python 便利的人来说并不那么令人震惊;为了方便起见,C/C++ 可能被证明过于简陋。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 2014-12-19
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多