美文网首页
OS - 一文带你快速精通程序、进程、线程、纤程

OS - 一文带你快速精通程序、进程、线程、纤程

作者: zzj0990 | 来源:发表于2021-02-05 18:38 被阅读0次

    以下本文都是在OS角度说的。

    面试高频:进程和线程有什么区别?

    • 非专业回答:进程就是一个程序运行起来的状态,线程是一个进程中的不同的执行路径
      专业回答:进程是OS分配资源的基本单位,线程是执行调度的基本单位
      分配资源最重要的是:独立的内存空间,线程调度执行(线程共享进程的内存空间,没有自己独立的内存空间)

    • 纤程:用户态的线程,线程中的线程,切换和调度不需要经过OS
      优势:1:占有资源很少 OS : 线程1M Fiber:4K 2:切换比较简单 3:启动很多个10W+
      截止本文发布时支持内置纤程的语言:Kotlin Scala Go Python(lib)... Java? (open jdk : loom)

    JAVA中对纤程的支持:目前没内置,期望内置

    利用Quaser库(不成熟)
    <dependencies>

    <dependency>
    <groupId>co.paralleluniverse</groupId>
    <artifactId>quasar-core</artifactId>
    <version>0.8.0</version>
    </dependency>
    </dependencies>

    // 线程版本:
    import co.paralleluniverse.fibers.Fiber;
    import co.paralleluniverse.fibers.SuspendExecution;
    import co.paralleluniverse.strands.SuspendableRunnable;
    public class HelloFiber {
        public static void main(String[] args) throws  Exception {
            long start = System.currentTimeMillis();
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    calc();
                }
            };
            int size = 10000;
            Thread[] threads = new Thread[size];
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(r);
            }
            for (int i = 0; i < threads.length; i++) {
                threads[i].start();
            }
            for (int i = 0; i < threads.length; i++) {
                threads[i].join();
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);
        }
        static void calc() {
            int result = 0;
            for (int m = 0; m < 10000; m++) {
                for (int i = 0; i < 200; i++) result += i;
            }
        }
    }
    // 大概耗时7s
    
    // 纤程版本
    import co.paralleluniverse.fibers.Fiber;
    import co.paralleluniverse.fibers.SuspendExecution;
    import co.paralleluniverse.strands.SuspendableRunnable;
    public class HelloFiber2 {
        public static void main(String[] args) throws  Exception {
            long start = System.currentTimeMillis();
            int size = 10000;
            Fiber<Void>[] fibers = new Fiber[size];
            for (int i = 0; i < fibers.length; i++) {
                fibers[i] = new Fiber<Void>(new SuspendableRunnable() {
                    public void run() throws SuspendExecution, InterruptedException {
                        calc();
                    }
                });
            }
            for (int i = 0; i < fibers.length; i++) {
                fibers[i].start();
            }
            for (int i = 0; i < fibers.length; i++) {
                fibers[i].join();
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);
        }
        static void calc() {
            int result = 0;
            for (int m = 0; m < 10000; m++) {
                for (int i = 0; i < 200; i++) result += i;
            }
        }
    }
    // 大概耗时3秒,纤程之间的切换很轻盈,是在用户态内部进行的,不需要os参与
    

    大家可以尝试:目前是10000个Fiber -> 1个JVM线程,想办法提高效率,10000Fiber -> 10份 -> 10Threads

    纤程的使用的场景

    纤程 vs 线程池:很短的计算任务,不需要和内核打交道,并发量高!

    进程创建和启动

    fork and exec.png
    linux是c语言写的,它对外提供一些类库和接口,比如fork(),创建进程调用系统的函数fork() 产生一个子进程,其实内部还是clone方式产生的,即从父进程克隆出一个

    僵尸进程 & 孤儿进程

    • 僵尸进程:父进程产生子进程之后,会维护子进程的一个PCB结构,如果子进程退出了,由父进程释放;如果父进程没有释放,那么子进程成为一个僵尸进程。
    • 孤儿进程:子进程结束之前,父进程已经退出
      孤儿进程会成为init进程的孩子,由1号进程维护

    进程调度(了解)

    Linux 2.6采用CFS调度策略:Completely Fair Scheduler
    按优先级分配时间片的比例,记录每个进程的执行时间,,如果有一个进程执行时间不到他应该分配的比例,优先执行。
    默认调度策略:
    实时优先级分高低 : FIFO (First In First Out),
    优先级一样 : RR(Round Robin)
    普通: CFS

    • 多任务
      -- 非抢占式:除非进程主动让出cpu,否则一直运行
      -- 抢占式:由进程调度器强制开启或暂停某一进城的执行

    ————————————————————
    坐标帝都,白天上班族,晚上是知识的分享者
    如果读完觉得有收获的话,欢迎点赞加关注

    相关文章

      网友评论

          本文标题:OS - 一文带你快速精通程序、进程、线程、纤程

          本文链接:https://www.haomeiwen.com/subject/akfgtltx.html