4.5 协程

目录

4.5.1 相关概念

4.5.2 yield

4.5.3 Greenlet

4.5.4 Gevent

4.5.1 相关概念

目的

  单线程下实现并发

概念特性

  

4.5.2 yield 

 
yield send 得实例
import time
def wrapper(func):
    def inner(*args,**kwargs):
        ret =func(*args,**kwargs)
        next(ret)
        return ret
    return inner
@wrapper
def consumer():
    while True:
        x= yield
        print(x)

def producter(target):
    '''生产者造值'''
    # next(g)  #相当于g.send(None)
    for i in range(10):
        time.sleep(0.5)
        target.send(i)#要用send就得用两个yield
producter(consumer())
View Code

4.5.3 Greenlet

概念

安装

pip3 install greenlet

用法

实例

from greenlet import greenlet
import time
def eat(name):
    print('%s eat 1' %name)
    time.sleep(10)  #当遇到IO的时候它也没有切,这就得用gevent了
    g2.switch('egon')
    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('egon')#可以在第一次switch时传入参数,以后都不需要

4.5.4 Gevent

概念

  对程序内部协作式地调度,轻松实现并发同步或异步编程

  自动识别 阻塞 ,然后自行切换任务。不在需要手动

安装

pip3 install gevent

 相关方法

g1=gevent.spawn(func,1,2,3,x=4,y=5)  # 创建一个协程对象g1,spawn括号内第一个参数是函数名,后面可以多个参数,可以是位置实参或关键字实参,都是传给函数eat的
g=gevent.spawn(func2)

g1.join() #等待g1结束
g2.join() #等待g2结束
#或者上述两步合作一步:gevent.joinall([g1,g2])

gevent.sleep(2)  # 模拟的是gevent可以识别的io阻塞
g1.value  #拿到func1的返回值


# 当不使用 gevent.sleep(2),使用 time.sleep() 得时候需要导入这个
from gevent import monkey;monkey.patch_all() # 如果不导入直接使用 time.sleep() 会无法实现单线程并发
# 必须放到被打补丁者的前面,如time,socket模块之前

实例

  基本使用实例

from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat(name):
    print('%s eat 1' %name)
    time.sleep(2)
    print('%s eat 2' %name)
    return 'eat'
def play(name):
    print('%s play 1' %name)
    time.sleep(3)
    print('%s play 2' %name)
    return 'play'  #当有返回值的时候,gevent模块也提供了返回结果的操作

start = time.time()
g1 = gevent.spawn(eat,'egon')  #执行任务
g2 = gevent.spawn(play,'egon')  #g1和g2的参数可以不一样
# g1.join()  #等待g1
# g2.join()  #等待g2
#上面等待的两句也可以这样写
gevent.joinall([g1,g2])
print('',time.time()-start) #3.001171588897705

print(g1.value)
print(g2.value)

"""
egon eat 1
egon play 1
egon eat 2
egon play 2
主 3.019590377807617
eat
play
"""
View Code

   爬虫实例

from gevent import monkey;monkey.patch_all()  #打补丁
import gevent
import requests
import time
def get_page(url):
    print('get :%s'%url)
    response = requests.get(url)
    if response.status_code==200: #下载成功的状态
        print('%d bytes received from:%s'%(len(response.text),url))
start=time.time()
gevent.joinall([
    gevent.spawn(get_page,'http://www.baidu.com'),
    gevent.spawn(get_page, 'https://www.yahoo.com/'),
    gevent.spawn(get_page, 'https://github.com/'),
])
stop = time.time()
print('run time is %s' %(stop-start))
View Code

  待回调函数得爬虫实例

from gevent import joinall, spawn, monkey

monkey.patch_all()
import requests
from threading import current_thread


def parse_page(res):
    print('%s PARSE %s' % (current_thread().getName(), len(res)))


def get_page(url, callback=parse_page):
    print('%s GET %s' % (current_thread().getName(), url))
    response = requests.get(url)
    if response.status_code == 200:
        callback(response.text)


if __name__ == '__main__':
    urls = [
        'https://www.baidu.com',
        'https://www.taobao.com',
        'https://www.openstack.org',
    ]

    tasks = []
    for url in urls:
        tasks.append(spawn(get_page, url))

    joinall(tasks)

"""
DummyThread-1 GET https://www.baidu.com
DummyThread-2 GET https://www.taobao.com
DummyThread-3 GET https://www.openstack.org
DummyThread-1 PARSE 2443
DummyThread-2 PARSE 141762
DummyThread-3 PARSE 65694
"""
View Code

猜你喜欢

转载自www.cnblogs.com/shijieli/p/10342895.html
4.5