Python-Basis-20th

周四,晴,记录生活分享点滴

参考博客:https://www.cnblogs.com/alex3714/articles/5248247.html

Python版本:3.5

协程介绍

协程是一种用户态的轻量级线程。(协程是一个单线程,效率高)

好处:

  • 无需线程上下文切换的开销
  • 无需原子操作锁定及同步的开销
  • "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。
  • 方便切换控制流,简化编程模型
  • 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

缺点:

  • 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  • 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

yield实现协程操作(最底层)

import time
import queue
def consumer(name):  # def中有yield表示consumer是生成器
    print("--->starting...")
    while True:
        new_baozi = yield  # next(con)结束
        print("[%s] is eating baozi %s" % (name,new_baozi))
        #time.sleep(1)
 
def producer():
 
    next(con)  # 接收yield返回值
    next(con2)
    n = 0
    while n < 5:  # 当n=5时producer执行结束
        n += 1
        con.send(n)  # 从new_baozi开始,再次到yield结束
        con2.send(n)
        print("33[32;1m[producer]33[0m is making baozi %s" %n )
 
 
if __name__ == '__main__':
    con = consumer("c1")  # 创建一个生成器对象con
    con2 = consumer("c2")  # 创建一个生成器对象con2
    p = producer()  # 执行producer函数,p是函数的返回值

greenlet (gevent下的模块)

from greenlet import greenlet
 
 
def test1():
    print(12)
    gr2.switch()
    print(34)
    gr2.switch()
 
 
def test2():
    print(56)
    gr1.switch()
    print(78)
 
 
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

"""
12
56
34
78
"""

gevent

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet

import gevent
 
def foo():
    print('Running in foo')
    gevent.sleep(1)  # 模拟IO阻塞情况
    print('Explicit context switch to foo again')
 
def bar():
    print('Explicit context to bar')
    gevent.sleep(2)
    print('Implicit context switch back to bar')
 
# 协程下2秒钟可以打印结果,相对于串行节省1秒 
gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

示例

from gevent import monkey; monkey.patch_all()  # 补丁:最大程度监听IO阻塞
import gevent
from  urllib.request import urlopen
 
def f(url):
    print('GET: %s' % url)
    resp = urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))
 
gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.yahoo.com/'),
        gevent.spawn(f, 'https://github.com/'),
])
原文地址:https://www.cnblogs.com/chungzhao/p/13092212.html