一文快速了解进程、线程与协程

2023-11-09

进程与线程

进程是操作系统进行资源分配的基本单位,每个进程都有自己的独立内存空间。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

线程又叫做轻量级进程,是进程的一个实体,是处理器任务调度和执行的基本单位位。它是比进程更小的能独立运行的基本单位。线程只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

对于操作系统来说,一个任务就是一个进程(Process)。比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。

有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,进程内的这些“子任务”称为线程(Thread)。

由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。

协程

协程,又称微线程,是一种用户态的轻量级线程,协程的调度完全由用户控制(也就是在用户态执行)。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到线程的堆区,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

如果对内核态用户态不了解的话,可以先看博客《一文理解JVM线程属于用户态还是内核态

协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和线程切换相比,线程数量越多,协程的性能优势就越明显。不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。此外,一个线程的内存在MB级别,而协程只需要KB级别。

进程和线程的区别

每个线程都是一个轻量级进程(Light Weight Process),都有自己的唯一PID和一个TGID(Thread group ID)。TGID是启动整个进程的thread的PID。

例如,当一个进程被创建的时候,它其实是一个PID和TGID数值相同线程。当线程A启动线程B时,线程B会有自己的唯一PID,但它的TGID会从A继承而来。这样通过PID线程可以独立得到调度,而相同的TGID可以知道哪些线程属于同一个进程,这样可以共享资源(RAM,虚拟内存、文件等)。

线程进程的区别体现在6个方面:

  • 根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

  • 资源开销:每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一进程的线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。

  • 包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的。

  • 内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。

  • 影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

  • 执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。两者均可并发执行。

协程与线程的区别

  1. 一个线程可以有多个协程。

  2. 大多数业务场景下,线程进程可以看做是同步机制,而协程则是异步。

  3. 线程是抢占式,而协程是非抢占式的,所以需要用户代码释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。

  4. 协程并不是取代线程,而且抽象于线程之上。线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行。

进程间的通信方式(IPC)

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)

Linux IPC的主要方式

1.管道(pipe)

管道,通常指无名管道,是UNIX系统IPC最古老的形式。

管道是一种半双工(即数据只能在一个方向上流动)的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。

进程的亲缘关系指的是父子进程或者兄弟进程关系。

当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。

特点:

  1. 面向字节流,

  2. 生命周期随内核。

  3. 自带同步互斥机制。

  4. 半双工,单向通信,两个管道实现双向通信。

2.命名管道(namedpipe)

FIFO,也称为命名管道,它是一种文件类型,也是半双工的通信方式。多个进程都可以通过一个约定好的名字找到同一个管道。FIFO允许无亲缘关系进程间的通信。FIFO的通信方式类似于在进程中使用文件来传输数据,只不过FIFO类型文件同时具有管道的特性。在数据读出时,FIFO管道中同时清除数据,并且“先进先出”。

3.消息队列(messagequeue)

消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

特点:

  1. 消息队列可以认为是一个全局的一个链表,链表节点钟存放着数据报的类型和内容,有消息队列的标识符进行标记。

  2. 消息队列允许一个或多个进程写入或者读取消息。

  3. 消息队列的生命周期随内核。

  4. 消息队列可实现双向通信。

但是当发送到消息队列的信息量大或操作频繁的场合,需要拷贝的时间也就越多,此时可以采用共享内存通信。

4.共享内存(shared memory)

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。

共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制(如信号量)配合使用来实现进程间的同步和通信。

特点:

  1. 不用从用户态到内核态的频繁切换和拷贝数据,直接从内存中读取就可以。

  2. 共享内存是临界资源,所以需要操作时必须要保证原子性。使用信号量或者互斥锁都可以。

  3. 生命周期随内核。

5.信号量(semophore)

信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

信号量主要实现进程之间的同步和互斥,而不是存储通信内容。

信号量定义了两种操作,p操作和v操作,p操作为申请资源,会将数值减去M,表示这部分被他使用了,其他进程暂时不能用。v操作是归还资源操作,告知归还了资源可以用这部分。

6.信号(signal)

信号是软件中断产生,用于进程间异步传递信息。信号可以用来直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

一般在shell中操作,进程获取信号进行处理,一共有64种信号,在shell中输入 kill -l 可查阅

7.套接字(socket)

套接字(有的时候被译为插座)也是一种进程间通信机制,与其他通信机制不同的是,套接字允许两个进程进行通讯,这两个进程可能运行在同一个机器上,也可能运行在不同机器上。

相对于共享内存可以多对多的读取与写入,套接字只能一对一。此外由于序列化等操作占用大量资源,相对于共享内存,套接字更适合传输少量数据。

进程通信方式总结

  1. 管道:速度慢,容量有限,只有父子进程能通讯

  2. 命名管道:任何进程间都能通讯,但速度慢

  3. 消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

  4. 共享内存:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全问题。

  5. 信号量:不能传递复杂消息,只能用来同步。

  6. 信号:用于通知接收进程某个事件已经发生。

  7. 套接字:可用于不同机器之间的进程间通信。

线程间的通信方式

锁(Lock)

锁机制包括互斥锁、条件变量、读写锁。

  1. 互斥锁提供了以排他方式防止数据结构被并发修改的方法。

  2. 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。

  3. 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

有关Java的锁机制,可以点击查看《详解Java多线程锁之synchronized》和《详解Java多线程锁之Lock和ReadWriteLock

有关条件变量,可以点击查看《Java多线程的可见性与有序性》中有关volatile的讲解。

信号量(Semaphore)

可以查看这篇博客《快速了解基于AQS实现的Java并发工具类》中有关Semaphore的讲解,感受下信号量如何在java线程通信中的使用。

信号(Signal)

可以查看这篇博客:《彻底搞懂Java的等待-通知(wait-notify)机制

协程间的通信方式

与线程不同,协程使用程序自定义的调度器进行调度,因此更容易控制协程之间的执行顺序,要想充分利用协程的调度模型,有一个完备的通信机制是很重要的。它主要应该有以下的功能:

  1. 能从一个协程发送消息到另一个协程,通知另一个协程特定的事件已经发生。

  2. 能够让协程在事件未发生之前挂起,等待事件发生后被调度并处理,从而有效让出CPU时间。

  3. 能够在消息中附带相应的数据。

能完成这样任务的模型很多,原理也不尽相同,但思路其实和线程的通信方式大体相同,这里以后再单独讲解。

补充

Nginx的进程通信有哪些

Nginx的进程通信分为三种类别:linux系统与Nginx通信(信号),master进程与worker进程通信(套接字),worker进程间通信(共享内存)。

  1. linux系统与Nginx通信
    答:linux系统与Nginx是通过信号进行通信的,通过信号控制Nginx重启、关闭以及加载配置文件等。比如:./nginx –s quit 向master进程发送信号。

  2. master进程与worker进程通信
    答:master在fork worker进程前,先调用socketpair,创建一个socket对用来master与worker进程间的通信。这个socket就是一个元素个数为2的数组channel,channel[0]用于master进程写入,channel[1]用于worker进程读入。

  3. worker进程间通信
    答:共享内存是最快的通信方式,是worker进程之间的通信方式。使用共享内存的好处是当多个进程使用同一块共享内存时,在任何一个进程修改了共享内存中的内容后,其他进程通过访问这段共享内存都能够得到修改后的内容。

进程七态

各种状态的意义:

  • 创建态:进程正在被创建。

  • 就绪态:可运行,但因为其他进程正在运行而暂时停止。

  • 运行态:正在占用CPU。

  • 结束态:进程正在从系统中消失。

  • 阻塞状态:该进程等待某个事件(比如IO读取)而停止运行,此时即使有CPU时间片也无法继续运行。

状态变化事件:

  • NULL => 创建态:一个进程被创建时的第一个状态。

  • 创建态 => 就绪态:当进程创建完成,进入就绪态。

  • 就绪态 => 运行态:CPU从就绪队列选择进程执行,进入运行态。

  • 运行态 => 结束态:当进程已经运行完成或出错时,进入结束态。

  • 运行态 => 就绪态:分配给进程的时间片使用完,进入就绪态。

  • 运行态 => 阻塞状态:进程执行等待事件,进入阻塞态。

  • 阻塞状态 => 就绪态:进程事件完成,CPU收到中断信号,进入就绪态。

进程状态变化中,还有一种状态叫挂起态,挂起态代表该进程没有占用内存空间,这跟阻塞状态是不一样。

挂起和阻塞的区别:

  • 挂起是一个行为,而阻塞是进程的一种状态。

  • 进程存放的位置不同:挂起是将进程移到外存中,而处于阻塞状态的进程还是在内存中。

  • 原因不同:导致进程被挂起的原因一般是内存不足或者是系统、用户的请求,协调、修改进程,研究进程的状态等,进程阻塞是进程正在等待某一事件发生,可能是等待资源或者响应等(eg.等待I/O完成等)而暂时停止运行。

  • 挂起对应的行为是激活,将外存中的进程调入内存中。而处于阻塞状态的进程需要其他进程或系统唤醒。

  • 挂起是被动的行为,进程被迫从内存中移至外存中。而进入阻塞可以看成是一个主动的行为(eg.进程I/O时,进程在等待I/O设备完成时,进程主动进入阻塞状态,I/O完成,进程被激活)

挂起态可以分为下面两种:

  • 阻塞挂起状态:进程在外存(磁盘)并等待某个事件的出现。

  • 就绪挂起状态:进程在外存(磁盘)激活后进入就绪态。

参考文档:

  1. 《深入理解计算机系统》

  2. 《深入理解Nginx》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文快速了解进程、线程与协程 的相关文章

  • 如何以编程方式找出我的 PermGen 空间使用情况?

    我正在尝试诊断java lang OutOfMemoryError PermGen Space在 Sun 的 Hotspot JVM 上运行时出现错误 并且想知道我的程序在不同时刻使用了多少 PermGen 空间 有没有办法以编程方式找出这
  • 如何在java中压缩/解压tar.gz文件

    谁能告诉我在java中压缩和解压缩tar gzip文件的正确方法我一直在搜索 但我能找到的最多的是zip或gzip 单独 我写了一个包装器公共压缩 http commons apache org compress called jarchi
  • Java Sqlite Gradle

    我对 gradle 和 java 还很陌生 我有一个使用 sqlite 的项目 它通过 intellij idea 运行良好 但我无法从终端运行它 它会抛出异常 java lang ClassNotFoundException org sq
  • 重构——套接字中的良好实践——简单的服务器-客户端 Swing 应用程序

    我使用单例和观察者模式编写了一个带有 Swing 接口的简单服务器 客户端程序 每个客户端都连接到服务器并可以发送消息 服务器将其收到的消息转发给其余的客户端 客户端使用 GUI 允许它们随时连接和断开与服务器的连接 该程序运行得很好 因为
  • 如何降低圈复杂度?

    我正在开发一个将 RequestDTO 发送到 Web 服务的类 我需要在发送请求之前验证该请求 请求可以从 3 个不同的地方发送 并且每个 请求类型 有不同的验证规则 例如请求1必须有姓名和电话号码 请求2必须有地址等 我有一个 DTO
  • Java中定义类型后同时初始化多个变量?

    这里需要一些语法方面的帮助 我正在尝试在定义类型后重新初始化多个变量 例如 int bonus sales x y 50 这工作正常 但是我想稍后在程序中将不同的值放入其中一些变量中 但我收到语法错误 bonus 25 x 38 sales
  • 在哈希图中存储字符和二进制数

    我正在尝试存储字母到二进制数的映射 这是我的映射 h 001 i 010 k 011 l 100 r 101 s 110 t 111 为此 我创建了一个哈希映射并存储了键值对 我现在想显示给定句子的相应二进制值 这是我的代码 package
  • 以点作为分隔符分割字符串

    我想知道我是否要在一个字符串上分割字符串 正确的方式 我的代码是 String fn filename split return fn 0 我只需要字符串的第一部分 这就是我返回第一项的原因 我问这个是因为我在 API 中注意到 意味着任何
  • 如果按下 Esc 则中断循环

    我用 JAVA 语言编写了一个程序 它使用 Scanner 类接受来自控制台的输入 现在我想将此功能添加到我的代码中 以便在用户按下 Esc 按钮时存在循环 while 到目前为止 我认为键盘类可以帮助我 但它就像扫描仪一样 我尝试使用事件
  • 此版本不符合 Google Play 64 位要求,添加库后仍然出现错误

    我正在 Play 商店上传一个视频编辑器应用程序 其中包含带有一些本机代码的库 所以我通过将其添加到 gradle 来使其兼容 64 位 ndk abiFilters armeabi v7a arm64 v8a x86 x86 64 添加了
  • 如何使用 Spring MVC 和 Thymeleaf 添加静态文件

    我的问题是如何添加 CSS 和图像文件等静态文件 以便我可以使用它们 我正在使用 Spring MVC 和 Thymeleaf 我查看了有关此主题的各种帖子 但它们对我没有帮助 所以我才来问 根据这些帖子 我将 CSS 和图像文件放在res
  • Java 中 static 关键字如何工作?

    我正在阅读Java教程 http docs oracle com javase tutorial index html从一开始我就有一个问题static字段或变量上的关键字 作为Java said here http docs oracle
  • 如何在 Java 中创建要打印到 JFrame 的 JLabels 数组

    我正在尝试制作一系列标签 每个标签都有一个来自函数的不同值 我不知道要使用的标签的确切数量 我的意思是可以打印任意数量的值 请帮我做这件事 很简单 只需一个方法返回一个数组或一些 JLabels 集合 并将它们全部添加到您的 JCompon
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 如何将任务添加到 gradle 中的主要“构建”任务

    当我尝试使用以下代码将任务添加到主构建任务时 rootProject tasks getByName build dependsOn mytask 当我跑步时它抱怨gradle w build输出 Where Build file line
  • 如何使用 SAX Java 解析器读取注释文本

    我只想使用 Java 中的 SAX 解析器读取 XML 文件中对象标记的注释 这是我的文件的摘要
  • 无法在 BlackBerry Playbook 上设置音量

    我在更改黑莓游戏书的音量时遇到问题 首先 我将 Android 应用程序重新打包到 Palybook 应用程序 我需要使用搜索栏更改黑莓剧本的音量 并在搜索监听器中设置音频管理器音量 这是代码 audioManager AudioManag
  • Java:基于 Web 的应用程序中的单例类实例

    我在 Web Application 中有这个 Singleton 类 public class MyDAO private static MyDAO instance private MyDAO public static MyDAO g
  • 在多线程环境中,Collections.sort 方法有时会抛出 ConcurrentModificationException。列表没有进行结构性修改

    package CollectionsTS import java util ArrayList import java util Collections import java util HashSet import java util
  • 编译时在代码中替换Java静态最终值?

    在java中 假设我有以下内容 fileA java class A public static final int SIZE 100 然后在另一个文件中我使用这个值 fileB java import A class b Object t

随机推荐

  • 数字成像系统笔记

    imaging algorithm specialist staff image quality engineer cmos sensor color science 3A 狭义3A 自动曝光 自动对焦 自动白平衡 广义 整个相机自动控制
  • 前脚背完这些接口自动化测试面试题,后脚就进了字节测试岗

    1 请结合你熟悉的项目 介绍一下你是怎么做测试的 首先要自己熟悉项目 熟悉项目的需求 项目组织架构 项目研发接口等 功能 接口 自动化 性能 是怎么处理的 第一步 进行需求分析 需求评审 研发和测试对需求达成统一的理解 第二步 架构师会输出
  • vscode终端颜色设置

    terminal integrated inheritEnv false editor fontSize 18 workbench colorCustomizations terminal background 200707 termina
  • 大数据简介&大数据应用场景

    背景 互联网信息化技术高速发展 企业生产过程中产生的数据量呈指数级上升 我们看一组统计 1986年 全球只有0 02EB也就是约21000TB的数据量 2007年 全球就是280EB也就是约300000000TB的数据量 翻了14000倍
  • vi查找替换命令详解

    一 查找 查找命令 pattern
  • Java项目(二)--Springboot + ElasticSearch 构建博客检索系统(3)- 分词器介绍

    分词器介绍 ES作为全文检索服务 势必要对原始的文本进行内容的拆分 才能进行有效的索引 而拆分原始内容到一个一个小的词 或语义单元 这部分的功能由ES的分词器去完成的 常见分词器 standard ES默认的分词器 会将词汇单元进行小写形式
  • VulnHub DC-8

    确定靶机IP地址 扫描靶机的开放端口 发现靶机开放端口有80 22 访问80端口 扫描网站的目录 发现敏感目录user 访问user目录 发现是登陆界面 使用工具查看网站的CMS 发现网站的nid会变化试一试会不会有sql注入漏洞 加个单引
  • 连接数据库时zeroDateTimeBehavior的作用

    在JDBC连接串中有一项属性 zeroDateTimeBehavior 没添加 zeroDateTimeBehavior 在操作值为0的timestamp类型时不能正确的处理 而是默认抛出一个异常 就是所见的 java sql SQLExc
  • MySQL必知必会 学习笔记 第二十八章 安全管理

    用户应该具有适当的访问权 既不能多也不能少 MySQL Administrator提供了图形界面 可用来管理用户和账号权限 MySQL创建一个名为root的用户账号 它对整个MySQL服务器有完全的控制 在日常工作中 决不能使用root 而
  • 浮点数的比较 C++

    浮点数的比较 C 用 来比较浮点数 返回的数是不确定的 计算机对浮点数的进行计算的原理是只保证必要精度内正确即可 我们在判断浮点数相等时 推荐用范围来确定 若x在某一范围内 我们就认为相等 至于范围怎么定义 要看实际情况而已了 float
  • YOLO(实时目标检测)V1-V2-V3简介和细节改进

    深度学习经典检测方法 one stage 一阶段 YOLO系列 核心优势 速度快 适合实时检测任务 缺点是通常情况下效果不是太好 two stage 两阶段 Faster rcnn Mask Rcnn系列 速度比较慢 但是效果不错 指标分析
  • 成语大全数据提取

    成语大全数据提取 Python数据处理 数据获取 提取成语 1 成语数据 从网站上搜集和爬取成语数据 成语大全的数据主要以 二进制存放在txt文件中 目前搜集的成语一共有 31341 条 其中绝大部分是四字成语 也不少五 六字的成语 总体来
  • 常量变量数据类型

    C语言学习笔记 基础篇 打印 printf include
  • PyTorch 官方博客:PyTorch Profiler v1.9 详解

    Profiler v1 9 的改进主要针对在运行时和 或内存上能耗最严重的执行步骤 同事将 GPU 和 CPU 之间的工作负载分配进行可视化 Profiler v1 9 新增五个主要功能包括 1 分布式训练视图 这有助于你掌握分布式训练任务
  • “山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛 A、H、K

    原题链接 A Seventeen 构造 输入 10 输出 1 2 3 4 5 6 7 8 9 10 说明 The following expression are considered right too 10 1 2 3 4 5 6 7
  • vue获取file文件的宽高等属性

    前言 我们在使用上传方法的时候 是可以拿到文件的file文件的 里面有很多文件信息 比如size大小等信息 但是没有宽高这类的 那么我们上传图片经常会需要这些属性 实现效果 实现步骤 1 核心js方法 if file var reader
  • Intellij IDEA plugins的插件无法下载

    在Intellij IDEA plugins下无法下载插件 显示超时 解决办法 1 选择HTTP PROXY SEXTTINGS gt Auto detect proxy settings gt ok gt 重新下载自己的插件 注 也可以指
  • STOMP 客户端开发

    STOMP 客户端开发 需求 客户端需要彼此通信 如主持人需要能够控制所有客户端的第三方应用开启权限 主要问题 目前的c s模型中是客户端主动连接服务器 客户端发出请求 服务器给出响应 缺少信息主动从服务器流向客户端的流程 可选方案 在客户
  • pinctrl和gpio子系统

    一 pinctrl子系统简介 Linux驱动讲究驱动分离与分层 pinctrl和gpio子系统就是驱动分离与分层思想下的产物 pinctrl子系统主要工作内容如下 获取设备树中的pin信息 根据获取到的pin信息来设置pin的复用功能 根据
  • 一文快速了解进程、线程与协程

    进程与线程 进程是操作系统进行资源分配的基本单位 每个进程都有自己的独立内存空间 由于进程比较重量 占据独立的内存 所以上下文进程间的切换开销 栈 寄存器 虚拟内存 文件句柄等 比较大 但相对比较稳定安全 线程又叫做轻量级进程 是进程的一个