多智能应用程序看起来可以随机加速

时间:2015-08-27 18:10:10

标签: java multithreading

我编写了一个Java代码,仅用于测试我的CPU将如何运行时必须执行此操作,我编写了一个循环,将在100亿次迭代中将var添加1:

public class NoThread {
    public static void main(String[] args) {
        long s = System.currentTimeMillis();
        int sum = 0;
        for (int i=0;i<=1000000;i++){
            for (int j=0;j<=10000;j++){
                for (int k = 0;k<=10;k++){
                    sum++;
                }
            }
        }
    long k = System.currentTimeMillis();
    System.out.println("Time" + (k-s)+ "   " + sum );
    }
}

代码在30 - 40秒后完成工作。

接下来,我决定将此操作拆分为10个线程,以使我的cpu更加哭泣,并在每个线程结束时说出我的编写时间:

public class WithThread {

public static void main(String[] args) {
Runnable[] run = new Runnable[10];
Thread[]thread = new Thread[10];
for (int i = 0; i<=9;i++){
    run[i] = new Counter(i);
    thread[i] = new Thread(run[i]);
        thread[i].start();
        }
    }
}

public class Counter implements Runnable {
private int inc;
private int incc;
private int sum = 0;
private int id;
public Counter(int a){
    id = a;
    inc = a * 100000;
    incc = (a+1)*100000;
}
@Override
public void run(){
        long s = System.currentTimeMillis();
        for (int i = inc;i<=incc;i++){
            for (int j=0;j<=10000;j++){
                for (int k = 0;k<=10;k++){
                    sum++;  
                }

            }
        }
        long k = System.currentTimeMillis();
        System.out.println("Time" + (k-s)+ "   " + sum + " in thread " + id);
    }
}

结果整个代码在18 - 20秒结束 - 所以快两倍,但当我在每个Thread结束时查看时,它发现了一些有趣的东西。每个线程都有相同的工作要做,但是4个线程在非常短的时间内(0,8秒)结束工作,其余的线程(6)在18到20秒内结束。我再次启动它,现在我有6个线程,快速时间,4个慢速。再次快速运行7次,慢速运行3次。快速和慢速线程的数量随机看起来。所以我的问题是为什么快速和慢速线程之间存在如此大的差异。为什么快速和慢速线程的数量是如此随机,这是特定于语言(Java)还是操作系统,CPU或其他东西?

1 个答案:

答案 0 :(得分:3)

在进入线程和处理器的工作过程之前,我将以更易理解的方式解释它。

<强>方案

Location A ------------------------------ Location B
     |     |_____________________________|
     |                     |
     |                200 Metres
     |
     |              Have to be carried to
400 Bags of Sand -------------------------- Location B
(In Location A)

因此,工人必须将每个沙袋从位置A运送到位置B,直到所有沙袋移动到位置B.

让我们假装工作人员一旦到达位置B,就会立即传送回去(为了争论)到位置A(但不是相反)。

案例1

劳动力人数= 1(男性人数)

所用时间= 2分钟(将1个SandBag从位置A移动到位置B的时间)

从位置A到位置B携带400 Sandbags所需的总时间

拍摄的总时间= 2 x 400 = 800分钟

案例2

劳动力人数= 4(男性人数)

所用时间= 2分钟(将1个SandBag从位置A移动到位置B的时间)

所以现在我们要在可用的劳动力中平分工作。

为每个工作人员指定的沙袋= 400/4 = 100

让我们说每个人都在同一时间开始工作。

从个人劳动力的位置A到位置B携带100个沙袋的总时间

个人劳动力的时间表= 2 x 100 = 200分钟

由于每个人都在同一时间开始工作,所有400 Sandbags将从位置A转移到位置B 200 mins

案例3

劳动力人数= 4(男性人数)

在这里,让我们说每个男士必须在一次转机中从位置A到位置B携带4个沙袋。

每位工人单次转运的沙袋总数= 4袋

所用时间= 12分钟(单次转移中从位置A到位置B移动4个沙袋的时间)

由于每个人都被迫携带4个沙袋而不是1个沙袋,这大大降低了他们的速度。

即使考虑到这一点,

1)我命令你从A到B携带1个沙袋,你需要2分钟。

2)我命令你在一次转移时从A到B携带2个沙袋,你需要花5分钟而不是理论4分钟,因为这是由于我们的身体状况和我们的体重所致携带。

3)我命令你在一次转移时从A到B携带4个沙袋,你需要12分钟而不是(第1点的Theoritical 8分钟,Point 2的Theoritical 10分钟),这也是因为人性。

所以现在我们要在可用的劳动力中平分工作。

为每个工作人员指定的沙袋= 400/4 = 100

每位员工的总转账次数= 100/4 = 25次转账

计算单个工人完成其全部工作所需的时间

单个工人的总时间= 12分钟x 25次转移= 300

所以,他们又花了100分钟而不是理论200分钟(案例2)

案例4

每位工人的单次转运沙袋= 100袋

由于任何人都无法做到这一点,所以他只是放弃了。

xx--------------------------------------------------------------------------------------xx

这与线程和处理器中的工作原理相同

下面

劳动力=处理器数量

总沙袋=线程数

单次转移中的沙袋= a(1)处理器同时处理的线程数

假设

可用处理器= 4

Runtime.getRuntime().availableProcessors()  // -> Syntax to get the no of available processors

注意:将每个案例与上面解释的实时案例相关联

案例1

for (int i=0;i<=1000000;i++){
    for (int j=0;j<=10000;j++){
        for (int k = 0;k<=10;k++){
            sum++;  
        }
    }
}

整个操作是系列过程,因此它会将执行时间视为它所设想的。

案例2

for( int n = 1; n <= 4; n++ ){  
    Thread t = new Thread(new Runnable(){
        void run(){
            for (int i=0;i<=250000;i++){     // 1000000 / 4 = 250000
                for (int j=0;j<=10000;j++){
                    for (int k = 0;k<=10;k++){
                        sum++;  
                    }
                }
            }
        }
    });
    t.start();
}

这里每个处理器将处理1个线程。所以它需要花费实际时间的1/4。

案例3

for( int n = 1; n <= 16; n++ ){  
    Thread t = new Thread(new Runnable(){
        void run(){
            for (int i=0;i<=62500;i++){     // 1000000 / 16 = 62500
                for (int j=0;j<=10000;j++){
                    for (int k = 0;k<=10;k++){
                        sum++;  
                    }
                }
            }
        }
    });
    t.start();
}

将创建总共16个线程,每个处理器必须同时处理4个线程。实际上,它会将处理器负载增加到最大值,因此会降低处理器的效率,从而导致每个处理器的执行时间增加。

完全接受1/4th of(1/4th of actual time) + performace degrade time(will definitely be higher than than the 1/4th of actual time)

案例4

for( int n = 1; n <= 100000; n++ ){       // 100000 - Just for argument sake
    Thread t = new Thread(new Runnable(){
        void run(){
            for (int i=0;i<=1000000;i++){     
                for (int j=0;j<=10000;j++){
                    for (int k = 0;k<=10;k++){
                        sum++;  
                    }
                }
            }
        }
    });
    t.start();
}

在这个阶段,创建和启动一个线程的成本更高(如果处理器中已经有更多的线程),而不是创建和启动前一个线程所花费的时间。随着同时线程数量的增加,它就会出现问题。大大增加处理器负载,直到处理器达到其容量,从而导致系统崩溃。

您在第一个中创建的线程具有较少执行时间的原因是因为在初始阶段期间处理器中的性能不会降低。但是,随着for循环的继续,每个处理器不必处理任何线程超过公平比(1:1),因此当处理器中的线程数增加时,您将开始遇到滞后。