python中协程与函数的区别_python协程和异步IO

1.并发、并行、同步、异步、阻塞、非阻塞

并发:是指在同一个时间段内,有几个程序都处于启动运行到运行结束之间

并行:在同一个时间点上,有几个程序同时运行

同步:当一个同步操作发出去后,调用者一直等待返回消息结果,才能进行后续的操作 比如操作文件 打开文件 读取文件 都是同步操作

异步: 当一个异步操作发出去后,调用者不能立刻得到消息结果 创建线程 都是异步操作

阻塞:调用结果返回之前,当前线程会被挂起来,一直处于等待消息通知,不能执行其他业务

非阻塞:调用结果返回之前,该函数不会阻塞当前线程 而立刻返回

2.IO多路复用select、poll、epoll

select

它通过一个select()系统调用来监视多个文件描述符,当select()返回后,该数组中就绪的文件描述符会被内核修改标志位,使进程能够获得这些文件描述符,从    而进行后续的修改

缺点:单个进程能够监视的文件描述符的数量存在最大限制 一般1024

poll

本质跟select()没有区别 但是poll没有限制,使用的是链表存储

epoll

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的    值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符    在系统调用时复制的开销。

另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,    而poll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描        述符,当进程调用epoll_wait()时便得到通知。

epoll实列

ContractedBlock.gif

ExpandedBlockStart.gif

1 importselectors,socket2 defaccept(sock, mask):3 conn, addr =sock.accept()4 print('accepted{}from{}'.format(conn,addr))5 conn.setblocking(False)6 sel.register(conn,selectors.EVENT_READ, read)7

8 defread(conn, mask):9 data = conn.recv(1024)10 ifdata:11 print('echoing{}to{}'.format(repr(data),conn))12 else:13 print('closing',conn)14 sel.unregister(conn)15 conn.close()16 sel =selectors.DefaultSelector()17 server =socket.socket()18 server.bind(('localhost', 9999))19 server.listen(500)20 server.setblocking(False)21 sel.register(server, selectors.EVENT_READ, accept) #注册事件,只要来一个连接就调accept这个函数,

22

23 whileTrue:24 events = sel.select()#这个select,看起来是select,有可能调用的是epoll,看你操作系统是Windows的还是Linux的

25 #默认阻塞,有活动连接就返回活动连接列表

26 print('事件',events)27

28 for key,mask inevents:29 callback =key.data30 callable(key.fileobj, mask)

View Code

客户端

importsocket,sys

server_address= ('localhost', 9999)#创建100个 TCP/IP socket实例

socks = [ socket.socket(socket.AF_INET, socket.SOCK_STREAM) for i in range(100)]#连接服务端

print('connecting to %s port %s' %server_address)for s insocks:

s.connect(server_address)

s.send(b'kehuduan')

data= s.recv(1024)print('服务端回来的数据{}'.format(data))if notdata:print('连接失败')

s.close()

3.什么是协成

可以暂停的函数(可以向暂停的地方传入值)

4.生成器

内含yiled关键字的函数

send方法

向生成器发送一个值,随后恢复执行

generator.send(value)

value参数是send方法向生成器发送的值,这个值作为当前yiled表达式的结果

随后生成器恢复执行 直到下一个yiled

ContractedBlock.gif

ExpandedBlockStart.gif

defgen_func():#1 可以产出值 2 可以接受值

yield 333t= yield 'www.baidu.com'

print(t)yield 2

yield 3

yield 4

return 'bobby'

if __name__ == '__main__':

gen=gen_func()#启动生成器方式两种 nex () send

gen.send(None)#gen.close()会触发一次

#gen.throw(Exception,'异常')抛出异常

#send方法可以传递值 进入生成器内部,同时还可以重启生成器执行到下一个yiled位置

next(gen)

ret= gen.send('888')print(ret)print(next(gen))print(next(gen))

View Code

thorw方法详解

在生成器暂停的地方抛出类型为type的异常

ContractedBlock.gif

ExpandedBlockStart.gif

defgen():

n=0whileTrue:try:yieldn

n+= 1

print('n的值{}'.format(n))exceptZeroDivisionError:print('铺货到异常ZerDivisionError')

g=gen()

ret=next(g)print('第一次的值{}'.format(ret))

ret=g.throw(ZeroDivisionError)print('第二次的值{}'.format(ret))

之所以第二次yield 的返回值还是 0,是因为在第一次 yield 的地方抛出了 ZeroDivisionError 异常,而该异常被 except 捕获,跳过了 n += 1的步骤。

在except 异常处理器中也可以看到,n 并没有改变,仍然是 0。

View Code

没有捕获并处理 throw 传入的异常,异常会回传给调用方。

def gen():

n = 0

while True:

yield n

n += 1

print('n的值{}'.format(n))

g = gen()

ret = next(g)

print('第一次的值{}'.format(ret))

try:

ret = g.throw(ZeroDivisionError)

except ZeroDivisionError:

print('第二次的值{}'.format(ret))

next(g)#对于已经通过抛出异常而退出的生成器再使用 next(g) 会持续抛出 StopIteration 异常。

生成器退出时没有 yield 新值,会抛出 StopIteration 异常。

def gen():

try:

yield 1

except Exception as e:

pass

yield 2

g = gen()

ret = next(g)

print('第一次的值{}'.format(ret))

ret = g.throw(TypeError, '类型错误哟')

# 虽然捕获并处理了 throw 传入的异常,但是由于处理完之后生成器没有后续语句而退出运行,而且并没有 yield 新值,所以会自动抛出一个 StopIteration 异常。

# 如果把 yield 2 注释打开,则不会抛出 StopIteration 异常,因为此时生成器暂停并返回了 2。

close方法

作用:在生成器函数暂停的地方抛出一个 GeneratorExit 异常。

这并不等价于 generator.throw(GeneratorExit),后面会说原因。

如果生成器抛出 StopIteration 异常(不管是由于正常退出还是因为该生成器已经关闭),或者抛出 GeneratorExit 异常(不捕获该异常即  可),close 方法不传递该异常,直接返回到调用方。而生成器抛出的其他异常会传递给调用方。

GeneratorExit 异常的产生意味着生成器对象的生命周期已经结束,因此生成器方法后续语句中不能再有 yield,否则会产生         RuntimeError。(而 throw 方法是期待一个 yield 返回值的,如果没有,则会抛出 StopIteration 异常。)

对于已经正常退出或者因为异常退出的生成器对象,close 方法不会进行任何操作。

第一种情况:不捕获 GeneratorExit 异常,close 方法返回调用方,不传递该异常。

ContractedBlock.gif

ExpandedBlockStart.gif

defgen():yield 1

yield 2

yield 3g=gen()

ret=next(g)print('第一次的值{}'.format(ret))

g.close()

next(g)

View Code

第二种情况:生成器自然退出抛出 StopIteration 异常,该异常不会传递给调用方,close 方法正常返回。

ContractedBlock.gif

ExpandedBlockStart.gif

defgen():try:yield 1

exceptGeneratorExit:print('生成器结束')

g=gen()

ret=next(g)print('第一次的值{}'.format(ret))

g.close()

View Code

第三种情况:在 GeneratorExit 抛出后还有 yield 语句,会产生 RuntimeError。

ContractedBlock.gif

ExpandedBlockStart.gif

defgen():try:yield 1

exceptGeneratorExit:print('生成器结束')yield 2g=gen()

ret=next(g)print('第一次的值{}'.format(ret))

g.close()

View Code

5.yiled from

3.3中新增加的特性

yiled from后面可以是迭代器 可迭代对象 甚至是生成器

ContractedBlock.gif

ExpandedBlockStart.gif

#使用yield

def gen(*args, **kw):for it inargs:for va init:yieldva

li= [1,2,3,4]

di= {'name':'gaofei','age':'25'}

tu= (6,7,8,9)

g=gen(li,di,tu)print(next(g))

View Code

ContractedBlock.gif

ExpandedBlockStart.gif

#使用yield from

def gen(*args, **kw):for it inargs:yield fromit

li= [1,2,3,4]

di= {'name':'gaofei','age':'25'}

tu= (6,7,8,9)

g=gen(li,di,tu)print(next(g))

View Code

生成器的嵌套

ContractedBlock.gif

ExpandedBlockStart.gif

defaverage_gen():

total=0

count=0

average=0whileTrue:

new_num= yieldaverage

count+= 1

print(count)

total+=new_numprint(total)

average= total/countdefproxy_gen():whileTrue:yield fromaverage_gen()defmain():

prox=proxy_gen()print(next(prox))print(prox.send(10))print(prox.send(20))if __name__=="__main__":

main()

View Code

概念

1.调用方 调用委派生成器的客户端

2.委托生成器 包含yield from表达式生成器函数

作用在子生成器和调用方之间生成建立一个双向通道

调用方可以通过send函数直接发送给子生成器 而子生成器的值也可以直接返回给调用方

3.子生成器 yiled from后面的生成器函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值