30、进程,线程,协程,并发,并行,yield生成器

1、概念回顾
首先要了解一些概念:
1、同步和异步:关注的是消息通信机制。
同步:就是在发出一个调用时,在没有得到结果之前,该调用就不返回。调用者主动等待这个调用的结果。
异步:调用在发出之后,这个调用就直接返回了,所以没有返回结果。在调用发出后,被调用者通过状态通知来通知调用者,或通过回调函数处理这个调用,然后调用者接到通知后去处理返回结果。
2、阻塞和非阻塞:关注的是程序在等待调用结果(消息返回值)时的状态。
阻塞:指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞:指在不能得到结果时,该调用不会阻塞当前线程。
3、并发和并行:关注的是多任务执行方式。
并发:不同的任务代码块交替执行。
并行:不同的任务代码块同时执行。
4、python中实现多任务有3种方式。
1、多进程
2、多线程
3、协程
线程依赖于进程,协程依赖于线程。

如何选择用哪种方式完成多任务呢?
1、计算密集型需要使用多进程。
2、IO密集型需要使用多线程
3、协程利用了当前线程在等待某个资源期间,执行其他函数。
4、爬虫其实访问一个网页中文字、图片,这一般都是文件读写IO,最好使用协程,因为协程是函数之间的切换,比线程切换效率更快。所以在爬虫中使用协程完成爬虫效率一般最高。

5、进程、线程、协程对比
请仔细理解如下的通俗描述
有一个老板想要开个工厂进行生产某件商品(例如剪子)
他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
这个老板为了提高生产率,想到3种办法:
在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式

简单总结:
进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很最大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
协程切换任务资源很小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发

2、协程回顾
协程,又称微线程,纤程。英文名Coroutine。
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。

协程和线程差异:
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

协程是使用生成器的yield实现的,下面看一些代码:

简单实现协程

import time

def work1():
while True:
print("----work1—")
yield
time.sleep(0.5)

def work2():
while True:
print("----work2—")
yield
time.sleep(0.5)

def main():
w1 = work1()
w2 = work2()
while True:
next(w1)
next(w2)

if name == “main”:
main()

运行结果:

----work1—

----work2—

----work1—

----work2—

----work1—

----work2—

----work1—

----work2—

----work1—

----work2—

----work1—

----work2—

…省略…

把work1和work2这个两个函数当做两个任务,那么这样表示两个任务可以切换了,并没有使用多线程或者多进程,也完成了多任务的实现。

yiele生成器还可以send传入参数,下面看一些代码:
def getContent():
while True:
url = yield
print(‘get content from %s’%url)

def getUrl(g):
url_list = [‘url1’,‘url2’,‘url3’,‘url4’,‘url5’]
for i in url_list:
g.send(i)

if name == ‘main’:
g = getContent()
next(g)
getUrl(g)
# 运行结果:

#get content from url1
# get content from url2
# get content from url3
# get content from url4
# get content from url5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值