博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
10月17日学习内容整理:协程
阅读量:6656 次
发布时间:2019-06-25

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

一、协程的基本性质

1、概念:协程是由用户程序自己控制调度的,是一种用户态的轻量级线程

2、作用:用来实现单线程下实现并发,从应用程序级别控制单线程下多任务的切换,注意一定是遇到IO才切且不可能有并行的概念

3、优缺点

(1)优点:

》协程的切换速度相比操作系统切换速度要小得多

》隐藏自己的IO阻塞,使程序尽可能的处在就绪态,争取更多的执行权限,来“骗”操作系统识别不到线程的IO操作

(2)缺点:

》无法利用多核优势

》一旦协程出现不可挽回的IO阻塞(因为不可能真正的隐藏IO阻塞),会阻塞整个线程

4、特点:

》必须在单线程的前提下

》修改共享数据不用加锁

 

二、代码实现协程

1、greenlet模块(第三方库)

(1)方法

g=greenlet(函数名)  得到一个协程对象

g.switch(参数)  切换到g去执行,第一次切的时候传参数,后面再切换就不用传参了

(2)特点

但是,遇到IO阻塞是无法自动切换的,但是比yield切换更方便点

#greenlet与yield一样都无法检测io然后自动切换,唯一一点好处是:greenlet比yieled的切换方式更加方便from  greenlet import greenletimport timedef eat(name):    print('%s eat 1' %name)    time.sleep(10)    g2.switch('alex')    print('%s eat 2' %name)    g2.switch()def play(name):    print('%s play 1' %name)    g1.switch()    print('%s play 2' %name)g1=greenlet(eat)g2=greenlet(play)g1.switch('alex')

 

2、gevent模块(第三方库):真正实现切换的效果

(1)作用:能够做到自己检测IO,并实现自动切换

(2)方法:

g=gevent.spawn(函数名,参数)  得到一个协程对象,异步提交任务

g.join()   等到g结束

gevent.joinall([g1,g2])等g1,g2都结束,注意是列表形式

g.value  取g的运行结果,注意要join后或者是运行完后才能拿结果,spawn后立刻取结果可能是None

gevent.sleep()   也是睡几秒,相当于IO阻塞

gevent只能直接识别自己的IO阻塞,若是time.sleep()就不会直接识别也就不会自动切换,要想解决这个问题,就必须在导入gevent之前先加补丁:

from gevent import monkey
monkey.patch_all()

或者

from gevent import monkey;monkey.patch_all()

这样协程就能识别所有的IO阻塞

from gevent import monkey;monkey.patch_all()     #这样就可以识别所有的IO阻塞import geventimport osfrom threading import current_thread#1.检测IO#2.自动切换import timedef eat():    print('%s eat 1' %current_thread().getName())    time.sleep(2)    print('%s eat 2' %current_thread().getName())def play():    print('%s play 1' %current_thread().getName())    time.sleep(1)    print('%s play 2' %current_thread().getName())start=time.time()g1=gevent.spawn(eat,)g2=gevent.spawn(play,)# g1.join()# g2.join()gevent.joinall([g1,g2])stop=time.time()print(stop-start)

 

3、基于协程的单线程并发

客户端:

from threading import Threadfrom socket import *def client():    c=socket(AF_INET,SOCK_STREAM)    c.connect(('127.0.0.1',8092))    while True:        c.send('hello'.encode('utf-8'))        data=c.recv(1024)        print(data.decode('utf-8'))if __name__ == '__main__':    for i in range(500):        t=Thread(target=client)        t.start()

 

服务端:

from gevent import monkey;monkey.patch_all()import geventfrom multiprocessing import Processfrom socket import *def server(ip,port):    s = socket(AF_INET, SOCK_STREAM)    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)    s.bind((ip,port))    s.listen(5)    while True:        conn,addr=s.accept()        print('%s:%s' % (addr[0], addr[1]))        g1=gevent.spawn(talk,conn,addr)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',8092)

 

转载于:https://www.cnblogs.com/wanghl1011/articles/7681892.html

你可能感兴趣的文章
Apache2 Web 服务器
查看>>
关于右键属性与du -sh显示的文件大小不一致的解决
查看>>
16秋进度条10
查看>>
WCF开发优秀博客园推荐
查看>>
Java自动装箱和拆箱
查看>>
Myeclipse10和Eclipse安装git插件 (亲测可用)
查看>>
Elementary Methods in Number Theory Exercise 1.4.9
查看>>
陶哲轩实分析引理17.1.16
查看>>
陶哲轩实分析 定义7.11(有限级数) 注
查看>>
数组中最大的子数组之和
查看>>
ASP.NET MVC and jqGrid 学习笔记 4-排序
查看>>
Java基础 - String的Intern方法详解(转)
查看>>
web前端页面解决中文传参乱码问题
查看>>
JavaScript多线程之HTML5 Web Worker
查看>>
[Vue CLI 3] public 目录没用吗
查看>>
PHP的生成图片或文字水印的类
查看>>
java中Memcached的使用(包括与Spring整合)
查看>>
远程桌面最新漏洞CVE-2019-0708 POC利用复现
查看>>
CentOS 卸载已安装软件
查看>>
11.22复习JS,浏览器内核
查看>>