线程进程协程

python(48): 进程,线程 ,协程

区别

进程:拥有代码和打开的文件资源、数据资源、独立的内存空间。

线程:线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。线程拥有自己的栈空间。

对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元。

进程--资源分配最小单位,线程,资源调度最小单位

协程:英文Coroutines,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。

最重要的是,协程不是被操作系统内核所管理,而完全是由程序(用户/库)所控制(也就是在用户态执行)。

这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

资源对比

进程:拥有自己独立的堆和栈,既不共享堆,也不共享栈,进程由操作系统调度;

线程:拥有自己独立的栈和共享的堆,共享堆,不共享栈,标准线程由操作系统调度;

协程:拥有自己独立的栈和共享的堆,共享堆,不共享栈,协程由程序员在协程的代码里显示调度

进程

进程与资源

学习 Linux 时,经常可以看到两个词:User space(用户空间)和 Kernel space(内核空间)。

简单说,Kernel space 是 Linux 内核的运行空间,User space 是用户程序的运行空间。为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。

地址空间

4GB 的进程虚拟地址空间被分成两部分:用户空间和内核空间

用户空间

用户空间按照访问属性一致的地址空间存放在一起的原则,划分成 5个不同的内存区域。 访问属性指的是“可读、可写、可执行等 。

代码段

代码段是用来存放可执行文件的操作指令,可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,它是不可写的。

数据段

数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量。

BSS段

BSS段包含了程序中未初始化的全局变量,在内存中 bss 段全部置零。

堆 heap

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈 stack

栈是用户存放程序临时创建的局部变量,也就是函数中定义的变量(但不包括 static 声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

上述几种内存区域中数据段、BSS 段、堆通常是被连续存储在内存中,在位置上是连续的,而代码段和栈往往会被独立存放。堆和栈两个区域在 i386 体系结构中栈向下扩展、堆向上扩展,相对而生。

线程

线程是操作操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位,一个进程内可以包含多个线程,线程是资源调度的最小单位。

线程资源和开销

同一进程中的多条线程共享该进程中的全部系统资源,如虚拟地址空间,文件描述符文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈、寄存器环境、线程本地存储等信息。

线程创建的开销主要是线程堆栈的建立,分配内存的开销。这些开销并不大,最大的开销发生在线程上下文切换的时候。

特点:

多线程并发时占用cpu时间由系统调度,所以多线程编程时需要考虑线程安全。

协程

类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程,因此协程又称微线程和纤程。

Python 和 Go 从语言层面提供了对协程很好的支持

调度开销

线程是被内核所调度,线程被调度切换到另一个线程上下文的时候,需要保存一个用户线程的状态到内存,恢复另一个线程状态到寄存器,然后更新调度器的数据结构,这几步操作设计用户态到内核态转换,开销比较多。

协程的调度完全由用户控制,协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作用户空间栈,完全没有内核切换的开销。

python协程的几个概念:

event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足条件发生的时候,就会调用对应的处理方法。

coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到时间循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。

task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

future:代表将来执行或没有执行的任务的结果,实际上和 task 没有本质区别。

async关键字:async 定义一个协程;

await 关键字:用来挂起阻塞方法的执行。

注意事项:在特殊函数内部不可以出现不支持异步模块相关的代码。(例:time,request)

协程优点缺点

优点

1.无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)

2.无需原子操作锁定及同步的开销

缺点

1.无法利用多核

2.进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

适用场景:爬虫程序,IO密集

爬虫协程:Python爬虫进阶 | 异步协程 - PythonGirl - 博客园

爬虫场景多协程与多线程比较:

多线程情况时,发起请求,此线程会等待响应,系统切换其他线程执行

多协程时,一个协程序发起请求后,代码级别切换执行另一个协程,能充分利用线程工作,并且没有系统上下文切换开销。

问题:

为什么线程是操作系统调度的最小单元?

一条线程是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

原文链接:https://blog.csdn.net/qq_37674086/article/details/126433311

posted @ 2024-01-25 19:15  布衣梦蝶1978  阅读(15)  评论(0编辑  收藏  举报