python 协程、进程、线程_Python的进程、线程和协程 · Donzy’s Blogs

0.前言

在计算机技术领域,吞吐量(throughput)是计算机在指定的一段时间内完成编程技术如何影响。本文主要讨论Python的多进程、多线程及协程等编程技术在不同场景下对系统吞吐量的影响。

1.CPU消耗型任务、I/O消耗型任务

计算机执行的任务分为CPU消耗型任务和I/O消耗型任务:

1.1 CPU消耗型任务:

大部分时间用来执行代码指令,在该任务执行期间,需要持续消耗处理器资源。除非被抢占或者时间片用尽,否则它们通常会一直运行。

1.2 I/O消耗型任务:

大部分时间用来提交I/O请求或者等待I/O请求。

外设的访问速度要远远慢于CPU速度,因而CPU在进行I/O操作时,不是马上可以获取I/O的数据,常常需要等待I/O。根据I/O等待方式的不同,I/O操作可以分为 阻塞I/O、非阻塞式I/O、I/O复用(select,poll,epoll,…)、信号驱动式I/O(SIGIO)、异步I/O(POSIX的aio_系列函数)

以下是几种I/O访问方式的概述阻塞I/O:

阻塞I/O的执行流程简述:

(1)申请后去I/O数据,内核缓冲区为空,进程阻塞,等待数据到达,然后复制到内核缓冲区域。

(2)将数据从内核缓冲区复制到应用程序缓冲区,然后进程结束阻塞

进程在获得I/O数据前一直阻塞非阻塞I/O:

进程不阻塞,一直采用轮询的方式,直到I/O数据准备好I/O多路复用:

I/O多路复用的函数也是阻塞的,但I/O多路复用是阻塞在select,epoll这样的系统调用上,而不是阻塞在I/O系统调用上。信号驱动式I/O:

进程通过信号与内核交互,内核缓冲区准备好I/O数据(期间,进程继续执行),然后数据从内核缓冲区拷贝到进程(期间进程阻塞),数据拷贝完成,进程阻塞结束异步I/O:

告知内核获取I/O数据,内核执行操作,完成操作后通知数据拷贝完成,进程读取数据。

讨论I/O操作时,经常会讨论两对概念:阻塞和非阻塞 、同步和异步

阻塞/非阻塞:进程访问数据时,数据没有就绪,进程是否需要等待,需要等待就是阻塞,反之就是非阻塞

同步/异步:同步需要进程主动读写数据,读写过程中会发生阻塞;异步只需要I/O操作完成的通知,不主动读写数据,交给操作系统内核完成数据读写。

上面讨论的I/O操作,阻塞I/O、非阻塞I/O、I/O多路复用、信号驱动式I/O都是同步的,只有异步I/O是属于异步的。

1.3 任务性质与多进程、多线程及协程

进程与线程比较类似,线程又称之为轻量级进程,一般认为线程在进程内部,是操作系统调度的基本单位,与进程共享地址空间、资源,但拥有自己独立的线程。

协程常被称为微线程,但协程不同于线程。

(1)调度方法不同,线程切换的上下文由操作系统内核保存和恢复,而协程在用户态保存和恢复,显然协程调度的代价要小的多。

(2)线程可以抢占,而协程不可以抢占,协程是通过让出CPU来实现调度的。

(3)协程占用更少的内存资源,只需要栈空间,而线程需要更多资源。

其实,从操作系统的角度看,协程只是单线程,通过让出CPU实现协程间切换,一次只有一个协程在执行,而多线程如果运行在多核CPU上,可以同时运行多个线程。单核CPU、多CPU消耗型任务

由于单核CPU,即使多进程/多线程,同一时间依旧只有一个进程可以执行操作,而CPU消耗型任务主要是执行指令,并且进程切换过程中需要消耗系统资源,多进程/多线程在这种情况下反而不如单进程效率高。而使用协程的情况与单线程的情况很相近,虽然协程比线程切换的消耗小,但是在CPU消耗型任务中,线程切换次数相对少,所以协程与线程效率也会比较相近。

多核CPU、多CPU消耗型任务

多核CPU下,可以同时运行多个进程/线程,实现CPU消耗型任务的并行计算,此时多进程/线程性能优于单进程/单线程。此时使用协程与单线程情况比较类似,效率同样会低于多进程/多线程。

单核CPU、多I/O消耗型任务

由于单核CPU,即使多进程/多线程,同一时间依旧只有一个进程可以执行操作,但是I/O消耗型任务经常会阻塞进程,此时其他进程可以被调度,合理利用这段CPU时间,虽然进程调度也会消耗资源,但是CPU时间利用更充分了,此时多进程/多线程性能应该是优于单进程/单线程。多I/O消耗型任务执行过程中,线程调度会更频繁一些,而协程调度消耗更低,所以协程执行效率应该是高于线程的。

多核CPU、多I/O消耗型任务

这种情况下显而易见,多进程/多线程性能会优于单进程。由于涉及到多核CPU,线程可以并行执行,线程的性能要高于协程。

2.Python中的进程、线程、协程

Python中的进程、线程及协程与上文讨论的进程、线程及协程在概念上是一样的,但实际上,Python中的线程与传统意义上讲的线程又不同。

CPython中有个GIL(Global Interpretor Lock)。顾名思义,就是Python解释器的一个全局锁。由于GIL的存在,Python的多线程即使在多核CPU上也不能并行运行,又有获得GIL锁的进程才能执行,也就是一个时间下只有一个线程在执行。一方面,线程切换的代价要比协程切换的代价大(线程由操作系统内核调度,协程调度发生在用户态),单从线程/协程切换的代价考虑,协程要比线程性能更好,但是另一方面,协程本质上是一个线程,而多线程技术是多个线程,多个线程被操作系统调度到的可能性要大于协程单个线程的可能性,这也会影响运行性能。综合上面两个方面Python在系统资源不紧张的情况下, Python线程与协程的性能可能是比较相近的。

对于多核CPU系统,需要并行运行线程的,可以用multiprocessing模块使用进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值