【问题标题】:Single vs Multi-threaded JMS Producer单线程与多线程 JMS 生产者
【发布时间】:2014-11-08 01:00:19
【问题描述】:

我想看看使用多线程生产者而不是单线程生产者会产生多少时间差异。我在本地机器上设置了一个 ActiveMQ,编写了一个生产者类,该类将在其构造函数中初始化并启动 JMS 连接。我将消息限制设置为 3M,将所有消息推送到 ActiveMQ 大约需要 50 秒。我只发送了一个字符串“hello world”3M 次。

然后我使用相同的生产者对象(一个连接但多个会话)并使用线程大小为 8 的 ExecutorService 运行它。在run 方法中,我会将 3M 除以 8,以确保每个线程发送的消息不超过 375000 条。在这种情况下,推送所有消息大约需要 60 秒。

ExecutorService service = Executors.newFixedThreadPool(8);

    for (int i = 0; i < 8; i++) {

        service.execute(producer);
    }

然后我创建了八个生产者,每个生产者都有自己的连接,并使用 ExecutorService 或线程大小为 8 运行它们。这次推送所有 3M 消息大约需要 68 秒。

for (int i = 0; i < 8; i++) {
        service.execute(new Producer());
    }

我想知道,为什么单线程生产者在这里表现更好?我对每个场景运行了大约 10 次,但结果保持不变。

【问题讨论】:

    标签: java multithreading jms


    【解决方案1】:

    我猜想管理多个会话的开销、它们与访问单个连接的同步以及线程切换可能是原因。

    为什么它应该在发送端使用多个线程更快地工作?该行只有一个,我看到的最大线程数是潜在的性能提升是两个 - 当第一个正在发送数据时,第二个正在准备其数据并且它们交替切换。

    【讨论】:

      【解决方案2】:

      您注意到的差异非常小,但我认为多线程处理器花费更多时间,因为线程之间的 cpu 资源并发。多线程处理器需要在线程之间共享 cpu,这可能会花费时间和额外的处理,有时还会使您的进程变慢。虽然单线程处理器不需要与其他线程共享 cpu,但它可以更高效地运行。另一方面与每个线程使用的资源有关。它们只使用内存中的字符串,它们不访问其他资源,如磁盘文件或数据库或 tcp 端口。在这种情况下,我认为单线程进程会比多线程进程快。

      【讨论】:

        【解决方案3】:

        我的钱花在 Calanais 概念上。您是否尝试过在应用程序运行时对其进行监控?像 VisualVM 这样的简单工具可以帮助您找出时间花在了哪里。

        【讨论】:

          【解决方案4】:

          由于几个原因,多线程可能比线程慢。一个是计算机的 CPU 是有限的,因此不能同时运行所有线程,从而使其速度变慢。另一个是你也有有限的内存量,导致线程需要更长的时间,因为它需要更多的内存。

          以这种方式考虑多线程,您有一个可以同时容纳 3 个的走廊。如果您同时通过该走廊的人较少,那么让所有人通过它将需要更长的时间。此外,相反,如果你试图让太多人同时通过它,走廊就会被堵塞,任何人都很难通过。

          这就是多线程在这里和其他一些情况下的糟糕之处。

          -------------------------- 编辑正在发生的事情: -------------------------------------------------- --

          您在问题中说过,您将为单线程程序将 3M 除以 8,以便它发送的消息不超过 375000 条。但是当你多线程时,你发送了所有的 3M 而不是 375000?如果这是真的,那么多线程比单线程慢的原因是因为 java 不能同时执行不同的线程,由于它的运行速度,它看起来像是同时执行,但它确实是在您设置的所有线程。而且它确实需要一点时间来切换它。几纳秒,因此需要更长的时间,因为即使多线程中的每个线程在单线程中运行相同的数量,它也需要在线程之间切换,这使得它花费的时间非常少,加起来是 8运行所需的额外秒数。

          【讨论】:

          • 嗨 PsyCode,我在 8 个内核和 8GB RAM 上运行了 8 个线程。我认为你的类比不适合这里。
          • 我在编辑中修复了它,我意识到你面临的问题是
          【解决方案5】:

          从 JMS 应用程序的角度来看,您已将应用程序编写为多线程;多个会话,每个会话都有自己的 JMS 生产者对象,由单独的线程驱动。假设您的应用程序没有对资源(例如锁等)的争用,这很好。

          就发送消息的效率而言,这取决于 JMS 提供程序在客户端和服务器端的实现效率。 JMS 实现中是否存在任何锁定或争用?也许它试图通过同一个套接字发送所有内容 - 在这种情况下存在争用。或者可能还有其他锁。

          可能在底层队列数据结构服务器端有一个锁服务器端。

          要回答您的问题,确实需要详细了解特定 JMS 提供程序。

          【讨论】:

            【解决方案6】:

            到 Broker 的连接使用单个 TCP/IP 连接通过网络推送每条消息。在大多数情况下,多个线程在同一连接上写入生产者没有任何优势,因为所有调用在通过 JMS 层进入有线协议层时都将变为串行。在您的情况下,由于线程调度加上锁争用加上管理线程池的开销,它需要更长的时间。

            要考虑的另一件事是,根据您的生产者和您发送到消息的目的地,将同步发送到代理,并且生产者将阻止等待来自代理的确认消息已被存储并获胜'不要迷路。这会产生很大的开销,但对于保证消息传递是必需的。即使您使用多个连接,所有连接的吞吐量也会受到运行代理的磁盘速度的限制,因为它必须首先写入所有持久消息。

            尝试和优化您的代码确实超出了 StackOverflow 的范围,您需要进行一些研究并了解 JMS 代理架构的含义以及您使用的代理的调整功能。如果您的线程为每条消息发送打开一个新连接,这将对性能造成很大影响,因为建立新连接是一项昂贵的操作,因此我建议您将 JMS 连接池也作为提高客户端性能的一种方式。

            对于您的情况,您可以查看异步发送或在事务中发送批量消息,以减少每次发送所需的时间。

            【讨论】:

            • 谢谢蒂姆,在我的最后一个场景中,每个线程都会打开一个全新的连接,所以没有连接共享但仍然没有改善。可能是因为我在同一台机器上同时运行 MQ Server 和 Producer?
            • Tim,我从来没有要求过代码优化。我想知道为什么多线程生产者在这里执行得更慢。您的评论仍然没有针对我的问题。
            • 因为多线程并不总是等于更快的性能。
            猜你喜欢
            • 2017-02-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多