python协程

1.协程优缺点及发展:

优点:

   1.协程 又称微线程 是一种轻量级线程  携程有自己的寄存器 上下文 和栈 携程能保留上一次调用时的状态

   2.协程优点和缺点 :

   3.无需线程上下文切换的开销

   4.无需原子操作锁定及同步的开销

   5.高并发 高扩展性 低成本

缺点:

   1.无法利用多核资源

   2.阻塞操作会阻塞整个程序

进程、线程、协程比较:

  1.进程是资源分配的单位,进程间切换需要大量资源,效率低,

  2.线程是操作系统调度的单位,线程间切换占用资源适中,效率适中

  3.协程利用等待或阻塞时间去执行其他任务,占用资源最少,效率高

 备注:进程直接数据不共享、每个进程都是独立的, 线程之间可以资源共享,但需要注意不然容易造成死锁。

Python中协程的发展:

  • Python2中使用 yield+send()语法。
  • Python3.3中引入 yield from 可以接收返回值。
  • Python3.4中引入了 asyncio 模块,直接内置了对异步IO的支持。
  • Python3.5增加了 async 和 await 关键字。
  • Python3.7使用 async def + await 的方式定义协程。

 

2.协程的意义:

充分利用IO的堵塞时间去执行别的任务

 

 

3.创建协程的方式:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
import time
import asyncio
import  requests
from greenlet import greenlet
'''
推荐使用asyncio方式实现协程
'''

#________________________________asyncio方法实现协程(python3.4后支持)_________________________________________________________
##方式一:
async def taskIO_1():
    print('开始运行IO任务1...')
    await asyncio.sleep(2)
    print('IO任务1已完成,耗时2s')
    return taskIO_1.__name__

async def taskIO_2():
    print('开始运行IO任务2...')
    await asyncio.sleep(3)
    print('IO任务2已完成,耗时3s')
    return taskIO_2.__name__


if __name__ == '__main__':
    start = time.time()#获取时间戳
    loop = asyncio.get_event_loop()#创建事件循环
    tasks = [taskIO_1(), taskIO_2()]
    loop.run_until_complete(asyncio.wait(tasks)) # 完成事件循环,直到最后一个任务结束
    print('所有IO任务总耗时%.5f秒' % float(time.time()-start))


##方式二:
async def test(i):
    r = await other_test(i)#挂起执行 other_test
    print(i,r)

async def other_test(i):
    r = requests.get(i)
    print(i)
    await asyncio.sleep(2)#挂起执行test()
    print(time.time()-start)
    return r
url = ["https://segmentfault.com/p/",
       "https://www.jianshu.com/p/badcbd",
       "https://www.baidu.com/"]


if __name__ == '__main__':
    loop = asyncio.get_event_loop()##获取消息循环体,,创建一个事件loop
    ##利用asyncio.ensure_future 生成一个task对象(loop.create_task也可以生成对象)
    ##task=[loop.create_task(test(i)) for i in url]
    task = [asyncio.ensure_future(test(i)) for i in url]
    start = time.time()
    #协程运行监控并返回结果
    loop.run_until_complete(asyncio.wait(task))#执行协程 (调用test())
    endtime = time.time()-start
    print(endtime)
    loop.close()



##____________________________________________greenlet实现协程______________________________________________
def test1():
    print('111')#2
    gr2.switch()#3.切换到test2函数
    print('333')#6
    gr2.switch()#7..切换到test2函数,从上一次执行位置向后执行

def test2():
    print('222')#4
    gr1.switch()#5.切换到test1函数,从上一次执行位置向后执行
    print('444')#8
    print('555')#9


if __name__ == "__main__":
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()#1.去执行test1函数



#____________________________通过生成器 yield实现协程_____________________________________________________
def consumer(name):
    print("要开始啃骨头了...")
    while True:
        print("\033[31;1m[consumer] %s\033[0m " % name)
        bone = yield
        print("[%s] 正在啃骨头 %s" % (name, bone))

def producer(obj1, obj2):
    obj1.send(None)    # 启动obj1这个生成器,第一次必须用None  <==> obj1.__next__()
    obj2.send(None)    # 启动obj2这个生成器,第一次必须用None  <==> obj2.__next__()
    n = 0
    while n < 3:
        n += 1
        print("\033[32;1m[producer]\033[0m 正在生产骨头 %s" % n)
        obj1.send(n)
        obj2.send(n)


if __name__ == '__main__':
    con1 = consumer("消费者A")
    con2 = consumer("消费者B")
    producer(con1, con2)

 

4.语法案例记录:

#!/usr/bin/env python
# encoding: utf-8

#________________________________________简单协程________________________________
import asyncio
async def do_some_work(x):
    print('Waiting'+str(x))
    await asyncio.sleep(x)
    print('Done')

#获取消息循环体,,创建一个事件loop
loop = asyncio.get_event_loop()
#调用协程函数,生成一个协程对象,此时协程函数并未执行
coro = do_some_work(3)
#将协程函数添加到事件循环,并启动
loop.run_until_complete(coro)

 

5.协程案例:

 

####______________________________________________异步-使用协程下载图片(第三方 gevent)________________________________________________________________________
monkey.patch_all()
def download(name, url):
    file_path= r'C:/Users/Administrator/Desktop/'
    obj = urllib.request.urlopen(url)#请求url
    content = obj.read()#读取文件对象
    #打开并写入
    with open(file_path+name, "wb") as f:
        f.write(content)   # 读取图片到1.jpg

def main():
    # 等待所有的协程开始运行结束
    gevent.joinall(
            [
                gevent.spawn(download, "1.jpg", "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2340497325,2166644129&fm=26&gp=0.jpg"),
                gevent.spawn(download, "2.jpg", "http://img.jingtuitui.com/759fa20190115144450401.jpg"),
                gevent.spawn(download, "3.jpg", "https://img.alicdn.com/imgextra/i3/827894246/O1CN01elaeCK1hEiIV640YT_!!0-item_pic.jpg_430x430q90.jpg")
            ]
    )


if __name__ == "__main__":
    main()



#______________________________________________________async异步下载文件________________________________________________________________
async def handler(url, file_path):
  headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0"
  }
  async with aiohttp.ClientSession() as session:
    r = await session.get(url=url, headers=headers)
    with open(file_path, "wb") as f:
      f.write(await r.read())
      f.flush()
      os.fsync(f.fileno())


url='https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2340497325,2166644129&fm=26&gp=0.jpg'
file_path = r'C:/Users/Administrator/Desktop/'
loop = asyncio.get_event_loop()
loop.run_until_complete(handler(url, file_path))

 

 

 

 

 

相关连接:

https://www.cnblogs.com/ghostlee/p/12190056.html .....................理解协程

https://blog.csdn.net/dianyin7770/article/details/101936045 ...............详解协程 

https://www.jianshu.com/p/f78b37a98a7f?open_source=weibo_search ................协程实现多任务1

https://blog.csdn.net/weixin_44621066/article/details/100840905 ..................协程实现多任务2

https://www.cnblogs.com/bubbleboom/p/14971052.html ................................python个版本协程写法

posted on 2021-04-21 14:58  chen_2987  阅读(128)  评论(0)    收藏  举报

导航