协程gevent模块和猴子补丁

# pip 装模块   greenlet和gevent


# 协程
    # 与进程、线程一样也是实现并发的手段
    # 创建一个线程、关闭一个线程都需要创建寄存器、栈等、需要消耗时间

# 协程本质上是一个线程
    # 能够在多个任务之间切换来节省一些IO时间
    # 协程中任务之间的切换时间开销,要远远小于进程或线程之间的切换

    # 4CPU中,进程一般创建4+1个进程 + 一个进程中线程为4*5 + 一个线程中创建500个协程,一般这是一台4CPU的机器电脑上能达到好的效率的并发程度,50000个并发。nginx这种负载均衡的东西就是这种思路

#
# def cosumer():
#     '''
#     生成器函数:
#     :return:
#     '''
#     while 1:
#         x = yield
#         print('处理消费了数据', x)
#
#
# if __name__ == '__main__':
#     c = cosumer()   # 得到生成器
#     next(c) # 走到生成器函数中的第一个yield
#     c.send(2)   # 将2给了生成器函数中的x并执行print然后又到了yield那


# # 在一个函数中控制另外一个函数,让这两个函数来回切换执行,下面用的是生成器实现的。协程效果
# def cosumer():
#     '''
#     生成器函数:
#     :return:
#     '''
#     while 1:
#         x = yield
#         print('处理消费了数据', x)
#
# def producer():
#     c = cosumer()
#     next(c)
#     for i in range(10):
#         print('生产了数据', i)
#         c.send(i)
#
# if __name__ == '__main__':
#     producer()


# 真正的协程实现任务之间的切换.
    # 真正的协程模块就是使用greenlet完成的任务之间的切换。省去了IO时间,当一个任务发生IO时,肯定会阻塞,此时这个时候去切换任务让另一个任务工作,另一个任务工作切换回来时,这个任务的IO时间正好结束,这就是协程想达到的效果,节省IO的切换时间
# import time
# from greenlet import greenlet
#
# def eat():
#     print('eating start')
#     g2.switch() # 切换到play中执行
#     print('eating end')
#
# def play():
#     print('playing start')
#     g1.switch() #切换到eat中执行
#
# g1 = greenlet(eat)  # eat任务放到greenlet中
# g2 = greenlet(play) # play任务放到greenlet中
# g1.switch() # 切换到eat任务执行到g2.switch()
# # 打印信息为
# # eating start
# # playing start
# # eating end
#
# # Process finished with exit code 0



# gevent模块
# import gevent
#
# def eat():
#     print('eating start')
#     gevent.sleep(1)   # 发生IO阻塞,切换到play
#     print('eating end')
#
# def play():
#     print('playing start')
#     gevent.sleep(1) # 发生IO阻塞,切换到eat
#
# g1 = gevent.spawn(eat)
# g2 = gevent.spawn(play)
# g1.join()   # 因为是异步的,如果不调用join,则直接执行到了下面,这样主进程就会结束,这里阻塞等待协程的结束
# g2.join()   


# gevent模块
# 协程,在一个线程中来回的切换。这个切换过程不是操作系统做的,而是gevent做的
# 在这个patch_all后面的所有模块中,发生的阻塞都会有gevent的效果
# #from gevent import monkey;monkey.patch_all()
# import time
# import gevent
#
# def eat():
#     print('eating start')
#     time.sleep(1)   # 发生IO阻塞,切换到play.因为有了mokey.patch_all所以这里等同于gevent.sleep(1),遇见IO就会切换
#     print('eating end')
#
# def play():
#     print('playing start')
#     time.sleep(1) # 发生IO阻塞,切换到eat
#     print('playing end')
#
# if __name__ == '__main__':
#     g1 = gevent.spawn(eat)
#     g2 = gevent.spawn(play)
#     g1.join()   # 阻塞等待协程执行结束
#     g2.join()   # 

# 协程任务之间的切换由程序代码(gevent)完成,只有遇到协程模块能识别到的IO操作的时候,程序才会进行协程切换,实现并发的效果



# 同步和异步(协程实现)
from gevent import monkey;monkey.patch_all()  #猴子补丁,必须放到最前面,这样所有模块中的方法发生了IO阻塞时,就会触发协程的切换
import time
import gevent

def task():
    time.sleep(1)
    print(12345)

def sync():
    for i in range(2):
        task()

def async():
    g_lst = []
    for i in range(10):
        g = gevent.spawn(task)  # 创建协程
        g_lst.append(g)
    gevent.joinall(g_lst)   # 阻塞等待协程完毕


async() # 异步的打印12345

   协程:能够在一个线程中实现并发效果的概念,能够巧妙的利用任务中的IO阻塞时间,在任务的执行过程中,检测到IO操作时就能够协程切换到别的任务中运行

posted @ 2018-10-28 15:38  _小溢  阅读(971)  评论(0编辑  收藏  举报