多线程不比单线程快(简单循环测试)

时间:2010-09-29 10:15:06

标签: java multithreading performance multicore intel

我正在尝试一些多线程构造,但不知何故,似乎多线程并不比单个线程快。我把它缩小到一个非常简单的测试,使用嵌套循环(1000x1000),系统只计算 下面我发布了单线程和多线程的代码以及它们的执行方式 结果是单个线程在 110 ms 内完成循环,而两个线程也需要 112 ms 。 我不认为问题是多线程的开销。如果我只将两个Runnable中的一个提交给ThreadPoolExecutor,它会在单个线程的一半时间内执行,这是有道理的。但是添加第二个Runnable会让它慢10倍。两个3.00Ghz核心都运行100% 我认为它可能是特定于PC的,因为其他人的PC在多线程上显示了双倍速度的结果。但那么,我能做些什么呢?我有一台Intel Pentium 4 3.00GHz(2个CPU)和Java jre6。

测试代码:

// Single thread:
long start = System.nanoTime(); // Start timer
final int[] i = new int[1];     // This is to keep the test fair (see below)
int i = 0;
for(int x=0; x<10000; x++)
{
    for(int y=0; y<10000; y++)
    {
        i++; // Just counting...
    }
}
int i0[0] = i;
long end = System.nanoTime();   // Stop timer

此代码的执行时间约为 110 ms

// Two threads:

start = System.nanoTime(); // Start timer

// Two of the same kind of variables to count with as in the single thread.
final int[] i1 = new int [1];
final int[] i2 = new int [1];

// First partial task (0-5000)
Thread t1 = new Thread() {
    @Override
    public void run() 
    {
        int i = 0;
        for(int x=0; x<5000; x++)
            for(int y=0; y<10000; y++)
                i++;
        i1[0] = i;
    }
};

// Second partial task (5000-10000)  
Thread t2 = new Thread() {
    @Override
    public void run() 
    {
        int i = 0;
        for(int x=5000; x<10000; x++)
            for(int y=0; y<10000; y++)
                i++;
        int i2[0] = i;
    }
};

// Start threads
t1.start();
t2.start();

// Wait for completion
try{
    t1.join();
    t2.join();
}catch(Exception e){
    e.printStackTrace();
}

end = System.nanoTime(); // Stop timer

此代码在 112 ms 中执行。

编辑:我将Runnables更改为Threads并删除了ExecutorService(为了简化问题)。

修改:尝试了一些建议

6 个答案:

答案 0 :(得分:11)

你绝对不想继续轮询Thread.isAlive() - 这没有充分的理由会耗费大量的CPU周期。请改用Thread.join()

此外,让线程直接递增结果数组,缓存行和所有内容可能不是一个好主意。更新局部变量,并在计算完成后执行单个存储。

编辑:

完全忽略了你正在使用奔腾4.据我所知,没有P4的多核版本 - 为了给出多核的幻觉,它有Hyper-Threading:两个逻辑核心共享一个物理核心执行单元。如果您的线程依赖于相同的执行单元,那么您的性能将与(或更差!)单线程性能相同。例如,您需要在一个线程中进行浮点计算,在另一个线程中进行整数计算以获得性能改进。

P4 HT实现受到了很多批评,较新的实现(最近的core2)应该更好。

答案 1 :(得分:4)

尝试稍微增加数组的大小。不,真的。

在同一个线程中按顺序分配的小对象最初将顺序分配。这可能在同一个缓存行中。如果你有两个内核访问同一个缓存行(然后micro-benhcmark基本上只是对同一个地址执行一系列写操作),那么他们将不得不争取访问。

java.util.concurrent中有一个类有一堆未使用的long字段。它们的目的是将不同线程经常使用的对象分成不同的缓存行。

答案 2 :(得分:2)

我对这种差异并不感到惊讶。您正在使用Java的并发框架来创建线程(尽管我没有看到任何保证甚至创建了两个线程,因为第一个作业可能在第二个作业完成之前完成。

在幕后可能会进行各种各样的锁定和同步,而您实际上并不需要进行简单的测试。简而言之,我认为问题是多线程的开销。

答案 3 :(得分:1)

你对i没有做任何事情,所以你的循环可能只是最优化了。

答案 4 :(得分:1)

您是否使用Runtime.getRuntime()检查了PC上的可用内核数量.availableProcessors()?

答案 5 :(得分:0)

您的代码只是增加一个变量 - 无论如何这是一个非常快速的操作。你在这里使用多个线程并没有获得太多收益。当线程1必须等待某些外部响应或执行一些更复杂的计算时,性能增益更加明显,同时主线程或其他线程可以继续处理并且不会等待。如果您计算更高或使用更多线程(可能是一个安全数字是您机器中的CPU /核心数),您可能会获得更多收益。