线程与协程的原理分析

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

昨天我们分析了一下进程和协程的性能,并且用实战的方式给大家演示了实际性能的差异,但是大家应该还记得协程是在线程里面的,那怎么来看呢?到底有多少协程在线程里面呢?今天我们就来看下。

协程代码分析

我们打一下断点,看一下线程

image.png

从上到下分别是main主线程指令监听器线程和这个协程的时间调度线程还有垃圾回收线程

没有协程,接着往下滑,能看到8个协程工作线程:

)UZK)C5SF@NI7$H`4J85REQ.png

这个forkjoin是一个异步框架,一共是8个线程,10万个协程才8个线程切换,相当于一个线程里面有12500个协程,然后我们增加线程数量到100万。

可以发现协程增加一倍,线程没有变还是8个,这就是为啥协程高效的原因,协程本来是go先搞的,后来java也怕没有未来也跟着搞起来了,你如果增加100万线程,那就是100万。

image.png

多线程和单线程性能

多线程一定比单线程快嘛?其实不一定,是有一个临界值的,在这个范围内,单线程快,我们来用代码演示一下:

private static final long count = 1000000000l;

public static void main(String[] args) {
    serial();
    try {
        concurrency();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void serial() {
    long start = System.currentTimeMillis();
    int a = 0;
    for (long i = 0; i < count; i++) {
        a += 5;
    }
    int b = 0;
    for (long i = 0; i < count; i++) {
        b--;
    }
    long time = System.currentTimeMillis() - start;
    System.out.println("serial:" + time + "ms);
}

private static void concurrency() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            int a = 0;
            for (long i = 0; i < count; i++) {
                a += 5;
            }
        }
    });

    thread.start();
    int b = 0;
    for (long i = 0; i < count; i++) {
        b--;
    }
    thread.join();
    System.out.println("concurrency :" + (System.currentTimeMillis() - start) + "ms");

}
  • 我们进行了10亿次计算的效果:串行花费:serial:613ms,并发花费:concurrency :315ms
  • 我们进行了1亿次计算的效果:串行花费:serial:64ms,并发花费:concurrency :39ms
  • 我们进行了1千万次计算的效果:串行花费:serial:10ms,并发花费:concurrency :6ms
  • 我们进行了1百万次计算的效果:串行花费:serial:2ms,并发花费:concurrency :2ms

此后一路持平,直到计算次数达到1000次,serial:0ms,并发花费:concurrency :1ms

当然这个计算结果跟电脑性能有关系,就是个实验数据。

猜你喜欢

转载自juejin.im/post/7127426168219205646