python-day35(协程,IO多路复用)

一. 协程

  协程: 是单线程下的并发,又称微线程,纤程,英文名Coroutine. 

  并发: 切换+保存状态

    协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的

  协程特点:

    1. 必须在只有一个单线程里实现并发

    2. 修改共享数据不需要加锁

    3. 用户程序自己保存多个控制流的上线文栈

    4. 一个协程遇到IO操作自动切换到其他协程(如何实现检测IO,yield,greenlet都无法实现,

      就用到了gevent模块(select机制))

  Greenlet模块

    单纯的切换(在没有IO的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度

  #真正的协程模块就是使用greenlet完成的切换
from greenlet import greenlet

def eat(name):
    print('%s eat 1' %name)  #2
    g2.switch('taibai')   #3
    print('%s eat 2' %name) #6
    g2.switch() #7
def play(name):
    print('%s play 1' %name) #4
    g1.switch()      #5
    print('%s play 2' %name) #8

g1=greenlet(eat)
g2=greenlet(play)

g1.switch('taibai')#可以在第一次switch时传入参数,以后都不需要  1
#安装
pip install greenlet
 1 # import time
 2 #
 3 # import greenlet
 4 # def fun1():
 5 #     time.sleep(2)
 6 #     print('约吗?')
 7 #     g2.switch()
 8 #     time.sleep(2)
 9 #     print('不约')
10 #     g2.switch()
11 # def fun2():
12 #     time.sleep(2)
13 #     print('你好')
14 #     g1.switch()
15 #     time.sleep(2)
16 #     print('你不好')
17 #
18 # g1 = greenlet.greenlet(fun1)
19 # g2 = greenlet.greenlet(fun2)
20 # g1.switch()
21 # ----------------------------------------------------
22 # import time
23 # import greenlet
24 # def f1(name):
25 #     print(name)
26 #     time.sleep(2)
27 #     a = g2.switch(name+'1')
28 #     print(a)
29 #
30 # def f2(name):
31 #     print(name)
32 #     time.sleep(2)
33 #     g1.switch(name+'1')
34 #
35 # a = time.time()
36 # g1 = greenlet.greenlet(f1)
37 # g2 = greenlet.greenlet(f2)
38 # g1.switch('hui')
39 # b = time.time()
40 # print(b-a)
greenlet练习

  Gevent模块

#安装
pip install gevent
#用法
g1 = gevent.spawn(func,多个参数) 创建一个协程对象g1, spawn(函数名,多个参数)
spawn是异步提交任务

g2 = gevent.spawn(func2)

g1.join() #等待g1结束,上面只是创建协程对象,这个join才是去执行
g2.join() #等待g2结束,

gevent.joinall([g1,g2]) #等待列表中的协程都结束
g1.value #拿到func1的返回值
gevent.sleep(2)# 睡2秒 遇到IO切换
# 不能识别time.sleep 解决办法 from gevent import monkey;monkey.patch_all()

  遇到IO阻塞是自动切换任务

import gevent
def eat(name):
    print('%s eat 1' %name)
    gevent.sleep(2)
    print('%s eat 2' %name)

def play(name):
    print('%s play 1' %name)
    gevent.sleep(1)
    print('%s play 2' %name)


g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,name='egon')
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
print('')

  gevent.sleep(2)模拟的是gevent可以识别的io阻塞,

  而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要下面一行的代码,打补丁,就可以识别

  from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前

  或者直接记忆成: 要用gevent, 需要将from gevent import monkey;monkey.patch_all()放到文件的开头

 1 # import gevent
 2 # import time
 3 # #gevent 不能识别 time.sleep
 4 # # 解决办法 from gevent import monkey;monkey.patch_all() 识别所有的IO 自动切换
 5 #
 6 # def func(n,):
 7 #     print('xxxx',n)
 8 #     gevent.sleep(2)
 9 #     # time.sleep(2) #不能识别
10 #     print('ccccc')
11 #
12 # def func2(m):
13 #     print('11111111',m)
14 #     gevent.sleep(2)
15 #     print('22222222')
16 # g1 = gevent.spawn(func,'alex')  #  异步提交任务
17 # g2 = gevent.spawn(func2,'马来西亚')
18 #
19 # # gevent.joinall([g1,g2]) #等多所有
20 # g1.join() #执行并等待异步提交的任务完成
21 # g2.join()#执行并等待异步提交的任务完成
22 # print('代码结束')
from gevent import monkey;monkey.patch_all()

二. IO多路复用

  IO模型

#1)  等待数据准备(Waiting for the data to be ready)
#2)  将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

  1. 阻塞IO

  2. 非阻塞IO模型

  3. IO多路复用

  4. 异步IO

猜你喜欢

转载自www.cnblogs.com/Thui/p/10065578.html