0

我目前正在研究分布式应用程序的性能。我的目标是一个网络组件。当前,对于每个连接,都有一个专用线程以阻塞模式处理套接字。我的目标是减少线程数(不降低性能),并尽可能提高性能。

我重新设计了网络组件以使用异步通信,并尝试使用 1 到 2 个线程进行整个网络处理。我做了一个简单的测试,我从一个节点循环写入并在另一个节点上读取,这是为了测试最大 nw 线程能力,我发现我的繁忙循环实现正在消耗 100% 的 cpu 并且每秒获得更多的操作,然后我们要求。所以我在现有的应用程序中集成了这个繁忙的循环实现。

我发现的问题是其他线程不允许这些异步 nw 线程获取完整的 cpu,即使我有一个 8 核系统并且我们使用的 cpu 不超过 400%。基本上,作为一名 C 程序员,我可以通过将我的 nw 线程绑定到一个核心并提高其调度优先级来解决这个问题,这样其他线程仍然可以在其他核心上运行。我无法在 Java 中做类似的事情。关于 Java 线程优先级的评论存在冲突。此外,我不想降低其他线程的优先级,因为它可能有其自身的副作用。

你将如何解决这个问题?

4

2 回答 2

3

我有一个库来支持 Linux 和 Windows 上的 Java 中的线程亲和性。https://github.com/peter-lawrey/Java-Thread-Affinity

如果您隔离 CPU,您可以确保您分配的 CPU 不会用于其他任何事情(除了不可屏蔽的中断)这在 Linux AFAIK 中效果最好。


如果您使用非阻塞 NIO 的忙等待而不是阻塞 IO,您可以获得更低的延迟结果。后者在负载下工作得最好,在较低的负载下,延迟会增加。

您可能会发现这个库很有趣https://github.com/peter-lawrey/Java-Chronicle它允许您每秒保存数百万条消息,可选地保存到第二个进程。

顺便说一句:线程优先级只是一个提示,操作系统可以自由地忽略它(并且经常这样做)


一个比较暖代码和冷代码的简单示例。它所做的只是重复复制一个数组并对其计时。一旦代码和数据升温,您就不会期望它会变慢,但即使在一台相当安静的机器上,它所需要的只是 10 毫秒的延迟,以显着减慢复制所需的时间。

public static void main(String... args) throws InterruptedException {
    int[] from = new int[60000], to = new int[60000];
    for (int i = 0; i < 10; i++)
        copy(from, to); // warm up
    for (int i = 0; i < 10; i++) {
        long start = System.nanoTime();
        copy(from, to);
        long time = System.nanoTime() - start;
        System.out.printf("Warm copy %,d us%n", time / 1000);
    }
    for (int i = 0; i < 10; i++) {
        Thread.sleep(10);
        long start = System.nanoTime();
        copy(from, to);
        long time = System.nanoTime() - start;
        System.out.printf("Cold copy %,d us%n", time / 1000);
    }
}

private static void copy(int[] a, int[] b) {
    for (int i = 0, len = a.length; i < len; i++)
        b[i] = a[i];
}

印刷

Warm copy 20 us
Warm copy 20 us
Warm copy 19 us
Warm copy 23 us
Warm copy 20 us
Warm copy 20 us
Cold copy 100 us
Cold copy 80 us
Cold copy 89 us
Cold copy 92 us
Cold copy 80 us
Cold copy 112 us
于 2012-08-09T17:44:15.467 回答
1

这对我来说确实有点过早的优化。你有一个 8 核系统,只使用 400% 的 CPU。是什么让您认为这不是 IO 绑定程序的教科书示例?是什么让您认为您的网络 IO 链没有达到极限?

@Peter 知道他的东西,我相信您可以破解处理器关联性并将您的关键线程强制到单个 CPU,但问题是它会让您的程序运行得更快吗?我真诚地怀疑它。模型 Java VM 在线程调度方面非常聪明,我建议它正在适当地完成它的工作。除非你有很好的相反证据,否则我会让它处理日程安排。如果大多数线程都在等待 IO,那么即使是优先级也没什么意义。

此外,是什么让您认为减少线程数会更好。这将大量代码从本机领域(即线程多路复用)转移到 Java 领域(即 NIO 代码)。如果您谈论的是 1000 个线程,那么我同意,但即使是 100 个线程也应该是处理连接的有效方法。

二十多年来,我已经进行了大量的线程编程,而且我从来没有强制线程亲和性。当然,确定线程池的大小并正确决定在何处应用线程池与专用线程是一门艺术,但强制 VM 以您认为应该的方式调度线程并不是很好地利用您的时间。花一些时间与分析器一起找出您的程序将时间花在哪里将是一个更好的投资恕我直言。

于 2012-08-10T01:10:48.180 回答