OS - 一文带你快速精通程序、进程、线程、纤程
以下本文都是在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.pnglinux是c语言写的,它对外提供一些类库和接口,比如fork(),创建进程调用系统的函数fork() 产生一个子进程,其实内部还是clone方式产生的,即从父进程克隆出一个
僵尸进程 & 孤儿进程
- 僵尸进程:父进程产生子进程之后,会维护子进程的一个PCB结构,如果子进程退出了,由父进程释放;如果父进程没有释放,那么子进程成为一个僵尸进程。
- 孤儿进程:子进程结束之前,父进程已经退出
孤儿进程会成为init进程的孩子,由1号进程维护
进程调度(了解)
Linux 2.6采用CFS调度策略:Completely Fair Scheduler
按优先级分配时间片的比例,记录每个进程的执行时间,,如果有一个进程执行时间不到他应该分配的比例,优先执行。
默认调度策略:
实时优先级分高低 : FIFO (First In First Out),
优先级一样 : RR(Round Robin)
普通: CFS
- 多任务
-- 非抢占式:除非进程主动让出cpu,否则一直运行
-- 抢占式:由进程调度器强制开启或暂停某一进城的执行
————————————————————
坐标帝都,白天上班族,晚上是知识的分享者
如果读完觉得有收获的话,欢迎点赞加关注