当前位置:   article > 正文

Python 系统线程和进程详解_python进程和线程的区别

python进程和线程的区别

一、进程和线程的区别

1.1 进程和线程对比

调度单位区别:进程是操作系统资源分配的基本单位,而线程是CPU任务调度和执行的基本单位、线程共享进程的内存/数据和资源

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

包含关系:一个进程内包含一个或多个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

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

1.2 线程间到底共享了哪些进程资源

1.2.1 线程私有资源

线程运行的本质其实就是函数的执行,函数的执行总会有一个源头,这个源头就是所谓的入口函数,CPU从入口函数开始执行从而形成一个执行流,只不过我们人为的给执行流起一个名字,这个名字就叫线程。

既然线程运行的本质就是函数的执行,那么函数执行都有哪些信息呢?

在《函数运行时在内存中是什么样子》这篇文章中我们说过,函数运行时的信息保存在栈帧中,栈帧中保存了函数的返回值、调用其它函数的参数、该函数使用的局部变量以及该函数使用的寄存器信息,如图所示,假设函数A调用函数B:

此外,CPU执行指令的信息保存在一个叫做程序计数器的寄存器中,通过这个寄存器我们就知道接下来要执行哪一条指令。由于操作系统随时可以暂停线程的运行,因此我们保存以及恢复程序计数器中的值就能知道线程是从哪里暂停的以及该从哪里继续运行了。

由于线程运行的本质就是函数运行,函数运行时信息是保存在栈帧中的,因此每个线程都有自己独立的、私有的栈区。

同时函数运行时需要额外的寄存器来保存一些信息,像部分局部变量之类,这些寄存器也是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息

从上面的讨论中我们知道,到目前为止,所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的。

以上这些信息有一个统一的名字,就是线程上下文,thread context。

1.2.2 线程间共享资源

进程地址空间的构成包括  栈区(通常是线程私有)、堆区、代码区、数据区 (后三者线程公有)

1.代码区

这里保存代码编译后的可执行机器指令

那么这些机器指令又是从哪里来的呢?答案是从可执行文件中加载到内存的,可执行程序中的代码区就是用来初始化进程地址空间中的代码区的。

2.数据区

进程地址空间中的数据区,这里存放的就是所谓的全局变量。

什么是全局变量?所谓全局变量就是那些你定义在函数之外的变量,在C语言中就像这样:

  1. char c; // 全局变量
  2. void func() {
  3. }

其中字符c就是全局变量,存放在进程地址空间中的数据区。

在程序员运行期间,也就是run time,数据区中的全局变量有且仅有一个实例,所有的线程都可以访问到该全局变量

3.堆区

堆区是程序员比较熟悉的,我们在C/C++中用malloc或者new出来的数据就存放在这个区域,很显然,只要知道变量的地址,也就是指针,任何一个线程都可以访问指针指向的数据,因此堆区也是线程共享的属于进程的资源。

4.栈区

通常来说栈区是线程私有的,栈区属于线程私有这一规则并没有严格遵守。

因为不像进程地址空间之间的严格隔离,线程的栈区没有严格的隔离机制来保护,因此如果一个线程能拿到来自另一个线程栈帧上的指针,那么该线程就可以改变另一个线程的栈区,也就是说这些线程可以任意修改本属于另一个线程栈区中的变量。

参考链接:线程间到底共享了哪些进程资源? - 腾讯云开发者社区-腾讯云

二、线程安全

同一个对象在一个进程还没有被更新完的时候就被其他线程进行修改了就是线程不安全的

2.1 Python 哪些操作是线程安全的

原子操作就是安全的

读数据是线程安全的,写数据才需要考虑线程安全问题

三、保证线程安全的方式

添加锁,保证同一时刻只有一个线程使用这个锁

信号量:控制同一时刻多个线程访问同一资源的线程数

四、进程间通信方式

Inter-Process Communication 进程间传递信号或数据

管道/匿名管道/有名管道 (Pipe):使用管道进行数据传输,每次读取的都是最新的数据,两个进程相互通信需要建立两个管道

信号(Signal): 比如用户使用Ctrl + C 产生终止信号

消息队列(MessageQueue): 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识,通过引入 from multiprocessing import  Queue 模块可以实现进程间通信   

参考示例:python多进程下的生产者和消费者模型_李俊的博客的博客-CSDN博客_python 多进程 生产者消费者

共享内存(share memory) :同时访问一块内存进行通信

套接字(socket):使用socket编程进行client和server连接

五、如何使用多线程/多进程

ThreadPoolExecutor (线程池) 多线程模块

ProcessPoolExecutor (进程池) 【底层使用os.fork()系统调用】

python 有GIL,对于CPU密集型的程序,使用多线程不仅不能加快响应速度,反而会降低响应速度

我们通常通过多进程的方式进行解决

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/789487
推荐阅读
相关标签
  

闽ICP备14008679号