博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python并发编程之协程
阅读量:5292 次
发布时间:2019-06-14

本文共 2270 字,大约阅读时间需要 7 分钟。

协程:基于单线程来实现并发 ,又称微程,纤程(Coroutine) 

并发的本质 :切换 + 保存状态   即由用户程序自己控制调度的

(1 协程的本质就是在单线程下由用户控制一个任务遇到阻塞就切换到另外一个任务执行以此来提升效率

  2 python线程属于内核级别的,即由操作系统控制(遇io或时间过长被迫交出cpu执行权限)

  3 单线程开启协程,一旦遇io就会从应用程序级别(而非操作系统)控制切换,以此来提升效率

协程的优点:

    1 协程的切换开销小,属于程序级别的切换操作系统感知不到

    2 单线程内就可以实现并发的效果,最大限度地利用cpu

           缺点:

    1 协程的本质是单线程下,无法利用多核,程序 ——》进程———》》线程————》》协程

    2协程是单个线程,因而一旦协和出现阻塞,将会阻塞整个线程

 协程的特点:

    1,单线程并发 2修改共享数据不需要加锁 3 在自己的的程序里保存多个控制上下文栈

 

  上下文栈  :(每一次代码执行和函数调用都会产生一个执行环境,称为执行上下文。

一个执行上下文(caller)又可以激活(调用)另一个执行上下文(callee),这时caller会暂停自身的执行把控制权交给callee进入callee的执行上下文,callee执行完毕后将控制权交回caller,callee可以用return或者抛出Exception来结束自己的执行。)

 

多个执行上下文会形成执行上下文栈,最顶层是当前执行上下文,底层是全局执行上下文。

切换的状态:1 发生阻塞(IO) 2计算时间过长

对于第二种纯计算的切换则会降低效率:

第一种任务在遇到io切,在利用阻塞的时间完成任务二的计算,效率的提升就在于此

yield 的状态保存属于代码级别的  

yield生成器需要初始化一次生成器然后再调用 send    /

greenlet模块可以非常简单的实现多个任务直接的切换 ,但当切换任务遇到 io 则原地阻塞仍没有解决

遇到io 自动切换来提升效率的问题   

Gevent模块:对于既有计算操作又有阻塞操作可以在执行任务1遇到阻塞就利用阻塞的时间去执行任务2来提升效率 可以实现并发同步或异步编程

用法:

  g1=gevent.spawn() #创建一个协程对象g1  ,spawn()  第一个参数是函数名

  g2 = gevent.spawn()

  g1.join() #等待g1结果 

  g2.join() #等待g1结果 

  #或者上述两者合作: gevent.joinall([g1,g2])

  g1.value #拿到func1 的返回值

send 可以把一个函数的结果传给另外一个函数,以此来实现单线程之间的切换

对于单线程下,我们不可避免的出现io操作,但如果我们能在自己的程序中控制单线程下的多个任务

能在一个任务遇到io阻塞时就切换到另外一个任务去计算,这样就保证了该线程能够在最大限度下处于

就绪状态(随时都可以被cpu执行的状态)

多线程并发套接字:

服务端:

from gevent import monkey;monkey.patch_all() import gevent from multiprocessing import Process from socket import * def talk(conn,addr):     while True:         try:             data=conn.recv(1024)             print('%s:%s [%s]' %(addr[0],addr[1],data))             if not data:break             conn.send(data.upper())         except ConnectionResetError:             break     conn.close() if __name__ == '__main__':     # server('127.0.0.1',8091)     s = socket(AF_INET, SOCK_STREAM)     s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)     s.bind(('127.0.0.1',8090))     s.listen(5)     while True:         conn, addr = s.accept()         print('%s:%s' % (addr[0], addr[1]))         g1 = gevent.spawn(talk, conn, addr) 客户端:
from socket import * c=socket(AF_INET,SOCK_STREAM) c.connect(('127.0.0.1',8090)) while True:     msg=input('>>: ').strip()     if not msg:continue     c.send(msg.encode('utf-8'))     data=c.recv(1024)     print(data.decode('utf-8'))

 

转载于:https://www.cnblogs.com/tianjianng/p/7681679.html

你可能感兴趣的文章
dedecms讲解-arc.listview.class.php分析,列表页展示
查看>>
Microsoft SQL Server Transact-SQL
查看>>
Font: a C++ class
查看>>
Extjs6 经典版 combo下拉框数据的使用及动态传参
查看>>
Java四种引用包括强引用,软引用,弱引用,虚引用
查看>>
【NodeJS】http-server.cmd
查看>>
iOS bundle identifier 不一致,target general的Bundle Identifier后面总是有三条灰色的横线...
查看>>
研磨JavaScript系列(五):奇妙的对象
查看>>
对比传统的Xilinx AMP方案和OPENAMP方案-xapp1078和ug1186
查看>>
面试题2
查看>>
selenium+java iframe定位
查看>>
js基础
查看>>
P2P综述
查看>>
细读 php json数据和JavaScript json数据
查看>>
第五章 如何使用Burp Target
查看>>
Sprint阶段测试评分总结
查看>>
Servlet3.0新特性
查看>>
java内存溢出怎么解决
查看>>
JS对象以及"继承"
查看>>
Ewebeditor最新漏洞及漏洞大全
查看>>