Java 线程内的代码比线程外的代码慢。。?

Java 线程内的代码比线程外的代码慢。。?,java,multithreading,performance,final,Java,Multithreading,Performance,Final,我正在尝试修改一些代码,以便它可以与多线程一起工作。在对某些代码执行Runnable操作时,我偶然发现性能下降 澄清一下:原始代码,我们称之为 //doSomething 像这样绕着它跑: Runnable r = new Runnable() { public void run() { //doSomething } } Executor executor = ...; for (int i = 0; i < 10; i++) { fi

我正在尝试修改一些代码,以便它可以与多线程一起工作。在对某些代码执行Runnable操作时,我偶然发现性能下降

澄清一下:原始代码,我们称之为

//doSomething
像这样绕着它跑:

Runnable r = new Runnable()
{
    public void run()
    {
        //doSomething
    }
}
Executor executor = ...;
for (int i = 0; i < 10; i++) {
    final int lap = i;
    Runnable r = new Runnable() {
        public void run() {
            long start = System.currentTimeMillis();
            //doSomething
            long duration = System.currentTimeMillis() - start;
            System.out.printf("Lap %d: %d ms%n", lap, duration);   
        }
    };
    executor.execute(r);
}
然后我将runnable提交给ChachedThreadPool执行器服务。这是我对这段代码进行多线程处理的第一步,以查看代码在一个线程中的运行速度是否与原始代码一样快

然而,情况并非如此。其中//doSomething大约在2秒内执行,Runnable大约在2.5秒内执行。我需要提到的是,与最初的//doSomethingElse相比,Runnable中的一些其他代码,比如说,//doSomethingElse,没有性能损失

我的猜测是//doSomething有一些在线程中运行时速度不快的操作,但我不知道它可能是什么,或者在这方面与//doSomethingElse的区别是什么

是不是因为使用了final int[]/float[]数组,才使得可运行的进程变得如此缓慢?//doSomethingElse代码也使用了一些韵母,但是//doSomething使用了更多韵母。这是我唯一能想到的

不幸的是,//doSomething代码很长,并且脱离了上下文,但我还是会在这里发布它。对于那些知道均值漂移分割算法的人来说,这是代码的一部分,其中均值漂移向量是为每个像素计算的。for循环

for(int i=0; i<L; i++) 
for(inti=0;i所有代码始终在“线程内”运行

您看到的减速很可能是由多线程增加的开销造成的。请尝试并行化代码的不同部分-任务不应太大,也不应太小。例如,您最好将每个外部循环作为单独的任务运行,而不是将最内部的循环作为单独的任务运行

但是,没有单一的正确方法来分割任务,这完全取决于数据的外观以及目标机器的外观(2核、8核、512核?)

编辑:如果重复运行测试会发生什么?例如,如果您这样做:

Runnable r = new Runnable()
{
    public void run()
    {
        //doSomething
    }
}
Executor executor = ...;
for (int i = 0; i < 10; i++) {
    final int lap = i;
    Runnable r = new Runnable() {
        public void run() {
            long start = System.currentTimeMillis();
            //doSomething
            long duration = System.currentTimeMillis() - start;
            System.out.printf("Lap %d: %d ms%n", lap, duration);   
        }
    };
    executor.execute(r);
}
Executor Executor=。。。;
对于(int i=0;i<10;i++){
最终int lap=i;
Runnable r=新的Runnable(){
公开募捐{
长启动=System.currentTimeMillis();
//剂量
长持续时间=System.currentTimeMillis()-开始;
System.out.printf(“圈数%d:%d毫秒%n”,圈数,持续时间);
}
};
执行人。执行人(r);
}

你注意到结果有什么不同吗?

当你创建一个新线程时,你总是有一个开销。如果你有一小段代码,你可能会遇到性能损失。 一旦您有了更多的代码(更大的任务),您就可以通过并行化来提高性能(线程上的代码不一定运行得更快,但您同时做了两件事)


只是一个细节:一个任务的大小可以如此并行化,这一决定仍然是值得的,这是并行计算中的一个已知主题:)

我个人认为没有任何理由这样做。任何程序都至少有一个线程。所有线程都是相等的。默认情况下,所有线程都以中等优先级(5)创建。因此,代码应该在主应用程序线程和您打开的其他线程中显示相同的性能


你确定你是在测量“做点什么”的时间,而不是程序运行的总时间吗?我相信您正在测量操作时间以及创建和启动线程所需的时间。

您没有确切说明如何测量所用的时间。显然有线程启动成本,但我推断您正在使用某种机制来确保这些成本不会扭曲您的图片

一般来说,在测量性能时,在测量小工件时很容易受到误导。我希望至少能多跑1000次,把整个过程循环起来

在这里,“无线程”和“线程化”情况之间的一个不同之处实际上是,您已经从拥有一个线程(正如已经指出的,您总是拥有一个线程)和两个线程,因此现在JVM必须在两个线程之间进行调解。对于这种工作,我不明白为什么会有不同,但它是不同的


我希望使用一个好的分析工具来真正深入研究这个问题。

如果您使用运行速度为260ms的程序,将其包装在Runnable中,并且只运行一次,那么是的,由于线程启动开销,它将花费更长的时间。一次运行某个东西并不是线程的好用途。请解释为什么要运行这个多线程。我提到其他代码在Runnable内部和外部一样快。但事实上,总运行时间更长的一个。此代码完成后,在Runnable内部大约需要3.5秒,而外部大约需要2秒。我想把这段代码作为一个实时应用程序的一部分多线程运行。巨for循环(从0到L)可以分成几个部分。根据您的编辑,并行化代码(和测试)看起来如何?@gustafc:“并行化”代码看起来与我发布的代码一样,只是粘贴到了Runnable的run()方法中。计时器也将位于run()方法内部。然后将Runnable提交给ExecutorService。我知道这还不是真正的并行,但如果这工作正常,我可以将伟大的循环分割成多个可运行的。原始线程在做什么?这是AWT事件线程吗?通过将功能从AWT事件线程移动到另一个线程,AWT事件线程可能会花费CPU周期重新绘制屏幕,这可能会降低新线程的速度。实际上,完成任务相当大(需要2秒)。对不起,我没提那件事。间接费用