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个版本协程写法
浙公网安备 33010602011771号