进程与线程的区别

引用Blog:

http://www.cnblogs.com/mindsbook/archive/2009/11/03/process_and_thread.html

 

进程和线程的定义

首先我们先要弄清楚二者的定义, 究竟什么是进程, 什么又是线程?

根据 wikipedia process 中的定义, 进程是一个计算机程序的实例,由一个或者多个线程组成.

同样在 wikipedia thread 中对线程的定义是: 线程的执行是由计算机的fork操作来将一个程序生成一个或者多个并发的运行任务.

在单核的计算机中, 线程并非 真正并行 的, 而是 分时的并发, 示意图如下:

http://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Multithreaded_process.svg/180px-Multithreaded_process.svg.png

也就是说多个线程无需等待另一个线程的完成,而只需要等待CPU的时间片.

在多核的计算机中,多个线程可以真正的并行,也就是同时执行,同时获得CPU时间片.

同样, 在现代计算机中, 通常都是 分时操作系统 (time sharing), 也就是不同的进程通过时间片来获得CPU的控制权, 来执行自己的代码. 同样,单核的系统进程也只能是并发的, 而多核的系统可以达到并行.

进程和线程的联系

二者的关系可以简单的一句话概括为, 通常, 一个进程可以包括多个线程, 一个线程只能属于一个进程.

一个进程可以生成多个线程,而这些线程之前共享地址空间和相应的资源, 在线程切换时, 并没有太多的开销.

http://farm3.static.flickr.com/2462/4070785749_4a001a75d2_o.png

图1: 进程的执行空间示意图

http://farm3.static.flickr.com/2436/4070785795_ff07b6930b_o.png

图2: 线程的执行空间示意图

从上面2个图可以很清楚地看到, 进程和线程在共享地址空间和资源的区别.

那么, 对于同样一个应用,我们可以选择 进程 来实现, 也可以选择 线程 来实现, 那么二者有什么区别呢? 我们应该如何选择呢?

进程和线程的区别

从本质上说,二者只是在 是否共享地址空间,及共享多少地址空间 上是有差别的,而至于其它的区别也都是 因为这个本质区别来引起的. 下面逐一地进行简单的说明.

关于共享地址空间

传统意义上, 进程之间是不共享地址空间的, 而线程是共享着进程的地址空间.

但是在Linux中, 会有不同, 请参考下面 特定操作系统的进程和线程 部分的详细说明.

安全性

因为进程之前是不共享资源和地址空间的,所以不会存在太多的安全问题(相比于线程).

而由于多个线程共享着相同的地址空间和资源,所以会存在线程之间有可能会恶意修改或者获取非授权数据的可能.

这也就是为什么近期, chrome和IE8相继开始使用多进程来替代之前的多线程(不同的tab之间).

健壮性

由于多个线程共享同一个进程的地址空间和相关的资源, 所以当一个线程出现crash,那么可能会导致相应的地址空间和资源 会出现问题,从而导致其它的线程也crash. 这个也很好理解,一个简单的大家可能都经历过的就是IE7吧, 当一个tab突然崩溃时,所有的tab都会崩溃,这时通常IE要重启(重启进程,重新生成线程).

而多进程则不存在这个问题, 因为不同的地址空间和资源, 当一个进程崩溃时, 并不会影响到其它进程. 同样,如果你用过chrome,如果一个tab崩溃了(chrome那搞笑的提示信息), 我们只需要关掉这个tab即可,并 不会影响到其它的tab.

http://farm3.static.flickr.com/2570/4070876881_4c6fb0b501_o.png

图三: chrome崩溃时的截图

性能

进程的安全性,健壮性是建立在独立的地址空间和独立的资源的条件下的, 所以进程的 启动关闭切换 相比于线程会有更多的开销. 而这种开销的差别在Windows下更加显著, 请参考下面 特定操作系统的进程和线程 部分的详细说明.

特定操作系统的进程和线程

进程和线程是依赖于特定的操作系统的, 譬如Windows和Linux在实现进程和线程就有很大的差异, 这一部分主要说明 Windows和Linux下进程和线程的一些特定的特征.

Windows

通常做过Windows多任务系统开发的程序员肯定会知道, Windows中的进程比线程有很大的开销, 要一定坚持使用线程, 那么为什么呢?

这里有个讨论可供参考: Why is creating a new process more expensive on Windows than Linux?

简单总结下, 原因:

  1. 这是Windows的设计的理念所致(多用户和并行的要求不高的特性)
  2. 在创建进程时,会有相当的系统调用

究竟有哪些额外的系统调用,请参考上面帖子.

Linux

让我们回到本文的摘要部分的引入, 我的室友提出的对于我而言 闻所未闻 的新观点.

那么, 在Linux下 进程和线程真的没有本质区别吗?

首先大家可以参考这个帖子, Threads vs Processes in Linux.

下面内容摘自 Threads vs Processes in Linux.

Linux uses a 1-1 threading model, with (to the kernel) no distinction between processes and threads
-- everything is simply a runnable task. *

On Linux, the system call clone clones a task, with a configurable level of sharing, among which are:

CLONE_FILES: share the same file descriptor table (instead of creating a copy)
CLONE_PARENT: don't set up a parent-child relationship between the new task and the old
(otherwise, child's getppid() = parent's getpid())
CLONE_VM: share the same memory space (instead of creating a COW copy)
fork() calls clone(least sharing) and pthread_create() calls clone(most sharing). **

forking costs a tiny bit more than pthread_createing because of copying tables and creating COW mappings for memory,
but the Linux kernel developers have tried (and succeeded) at minimizing those costs.

Switching between tasks, if they share the same memory space and various tables, will be a tiny bit cheaper
than if they aren't shared, because the data may already be loaded in cache. However,
switching tasks is still very fast even if nothing is shared -- this is something else that Linux kernel developers
try to ensure (and succeed at ensuring).

In fact, if you are on a multi-processor system, not sharing may actually be a performance boon:
if each task is running on a different processor, synchronizing shared memory is expensive.

上面其实已经讲得很清楚了,

  1. 对于内核而言, 进程和线程是 没有区别的
  2. 在用户的角度而言,区别在于如何创建(clone), 如果使用是 least shared ,那么就类似于进程的创建(最少共享)
  3. 如果使用的是 most sharing 那么就类似于线程的创建(最多共享)
  4. 由于Linux内核开发人员的努力和优化, 创建, 切换, 关闭 进程和线程之前的开销差异已经十分的小了

如何选择

如果你看到了这里, 应该会对进程和线程有较深入的理解, 那么我们该如何在面对多任务问题时选择呢?主要请考虑下面几个因素:

  1. 安全性要求
  2. 健壮性要求
  3. 性能要求
  4. 具体的平台

熟悉上面的具体的细节然后结合自己的应用场景, 做出最优的选择(通常做不到最优,次优即可), 这样就能够较好利用好 并发性(单核)或者并行(多核).

相关的技术细节

在结束本文之前, 我想谈下进程和线程相关的一些技术细节.

COW

COW即, Copy On Write, 具体的介绍可以参考 Copy On Write.

简单地说, COW是对下面场景的一种优化:

多任务系统对于初始时相同资源的共享, 只有当某个任务写这个资源时(更新), 才会 主动地在这个任务本地拷贝一份资源,从而不影响其它的任务.

例如, 资源author="zhutao", 这个变量资源, 在初始时由A,B,C三个任务共享author这个资源,

  1. 如果在整个过程, A,B,C三个任务都没有更改author, 那么整个系统只保留一份author资源的copy.
  2. 如果在过程中,B有修改author资源的操作,那么B会主动拷贝一份author, 然后再更改拷贝后author, 此时整个系统有2份author资源的copy.
  3. 以此类推, 一旦有更改的操作都会生成一份新的copy

那么从这个机制来看,它明显地有如下优势:

  1. 无需完全为每个任务生成资源拷贝, 而只是当修改时再生成拷贝
  2. 提高了任务之间切换的效率
  3. 提高了系统资源的利用率
  4. 其它

这个机制在Linux下已经得到了广泛的应用,这也是为什么Linux下进程和线程的开销差异小的原因.

线程安全(thread safety)

这个之前已经讨论过了,请参考我的博文 线程安全及Python中的GIL

进程同步

进程中的线程可能会在运行中形成不同的资源, 所以需要进行同步来达到数据的一致, 即所谓的 进程同步.

进程的同步方式有很多不同的方法, 如信号量, 锁, 事件等.

具体可以参考: Synchronization

根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
<think>嗯,用户问的是进程线程区别,我需要详细解释清楚。首先,我得回忆一下自己学过的操作系统知识。进程线程都是执行单元,但关键区别在于资源管理执行方式。 我记得进程是独立的,有自己独立的内存空间,而线程则共享进程的资源。这应该是主要区别之一。不过要分点说明,可能需要从定义、资源分配、切换开销、通信方式、稳定性等方面展开。 比如,进程之间切换需要更多的系统资源,因为要切换内存地址空间,而线程切换在同一个进程内,所以更轻量。这也就是为什么线程被称为轻量级进程。可以参考用户提供的引用[1][2],里面提到线程共享打开文件列表、虚拟地址空间等,所以更轻量。 然后,通信方式方面,进程间通信可能需要IPC机制,比如管道、消息队列,而线程可以直接读写进程数据段,所以更方便但需要同步机制,比如互斥锁。引用[3]里提到synchronizedvolatile的区别,这可能涉及线程同步的问题,但用户的问题主要是区别,可能需要点到为止。 稳定性方面,进程崩溃不会影响其他进程,但线程崩溃可能导致整个进程终止。这也是一个重要区别,用户可能关心多线程程序的稳定性问题。 另外,用户提供的引用[1]提到线程称为轻型进程,而传统进程是重型进程。引用[2]指出Linux下线程用task_struct表示,共享资源,所以更轻量。这些可以作为支撑点,在回答中引用。 需要确保回答结构清晰,分点列出区别,可能用表格会更直观,但用户示例里没有表格,所以可能用编号列表更合适。同时,用户需要中文回答,使用LaTeX格式时注意数学表达式的正确性,但这个问题可能涉及较少的数学符号,可能更多是技术术语。 最后,生成相关问题时要考虑用户可能的后续疑问,比如如何选择进程还是线程,优缺点比较,或者具体应用场景。比如多线程适合IO密集型,多进程适合CPU密集型任务。或者通信方式的具体实现,如管道共享内存的区别等。 现在检查是否有遗漏点:资源分配、切换开销、通信、创建销毁开销、稳定性、依赖关系。是的,这些点基本覆盖了主要区别。需要确保每个点都简明扼要,并适当引用提供的参考资料。</think>### 进程线程区别详解 #### 1. **定义基本概念** - **进程**:操作系统资源分配的基本单位,拥有独立的虚拟地址空间、文件描述符等资源。例如,浏览器音乐播放器属于不同进程[^1]。 - **线程**:CPU调度的基本单位,隶属于某个进程,共享进程的资源(如内存、文件句柄)。例如,浏览器中同时加载多个网页标签页可能使用多个线程[^2]。 #### 2. **资源分配共享** - **进程**:资源独立,进程间共享数据需通过进程间通信(IPC),如管道、共享内存。 - **线程**:共享进程的资源,可直接访问全局变量,但需同步机制(如互斥锁)避免冲突[^3]。 #### 3. **切换性能开销** - **进程切换**:涉及虚拟地址空间、内核栈等切换,开销大。 - **线程切换**:仅切换线程私有数据(如寄存器、栈),开销小,因此被称为轻量级进程。 #### 4. **通信方式** - **进程间通信**:需要显式使用IPC机制(如消息队列、Socket)。 - **线程间通信**:直接通过共享内存通信,但需处理同步问题(如条件变量、信号量)[^3]。 #### 5. **稳定性容错** - **进程**:一个进程崩溃不会影响其他进程(如浏览器崩溃不影响音乐播放器)。 - **线程**:一个线程崩溃可能导致整个进程终止(如浏览器某标签页崩溃可能关闭整个浏览器)。 #### 6. **创建销毁** - **进程**:通过`fork()`创建,需复制父进程资源(写时复制优化),销毁需回收所有资源。 - **线程**:通过`pthread_create()`创建,共享父进程资源,销毁仅释放线程私有资源。 #### 7. **典型应用场景** - **进程**:需要高隔离性的任务(如安全沙箱、独立服务)。 - **线程**:需要高并发且共享数据的任务(如Web服务器处理多请求)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值