最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Python Coroutine Async_协程、异步实例代码

XAMPP案例 admin 1068浏览 0评论

zzzzzv00000027

Python Coroutine Async

先谈谈我了解的语言中有哪些支持协程呢? golang,ruby,lua,python. 那协程作用又是什么呢?用最最最最简单的语言概括:

由我们的程序自己代替系统切换任务,最大可能的让系统认为程序是就绪状态,从而把cpu的执行权限分配给我们的程序。

python 的coroutine

任务切换

yeild + send

我们来看看线程切换都干了些什么?

  1. cpu执行func1.
  2. 系统法线func1执行到io操作了,或者计算量小的任务,调低func1的权重.
  3. 对比权重,发现func2权重现在是最高的了,将func2状态调为准备状态,保存func1上下文。
  4. 切换到func2上来执行。

参考1 https://www.cnblogs.com/russellyoung/p/python-zhi-xie-cheng.html

  1. import time
  2. def func1():
  3. while True:
  4. print('func1')
  5. yield
  6. def func2():
  7. g = func1()
  8. for i in range(10000000):
  9. i + 1
  10. next(g)
  11. time.sleep(3)
  12. print('func2')
  13. start = time.time()
  14. func2()
  15. stop = time.time()
  16. print(stop - start)

协程

协程就是单线程下的并发(并发、并行),是一种用户级别的轻量级线程,由用户控制调度的微线程。

干嘛用它? 这就要涉及到进程、线程、资源、状态、优先级等综合起来的东西。总的一句话概括就是,你借了系统的钱,系统每过一段时间就来问问你能不能还钱,然后你就一直跟系统打招呼,钱还在股市生娃呢,没控。

 

用法:

参考2:官方文档https://docs.python.org/3/library/asyncio-task.html

参考1最后的实例非常好

 

协程、异步

参考3 https://www.cnblogs.com/wangchengpei/p/10958043.html

  1. eventloop:(qt也有eventloop 狗头.jpg) 循环事件,类似一个循环队列,有事件注册,就会被执行。
  2. coroutine: 协程

在 Python 中常指代为协程对象类型,我们可以将协程对象注册到时间循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。

  1. task:任务,对协程对象的封装,包含了任务的各个状态。
  2. future:未执行任务。
  3. async/await:定义协程,阻塞。

eg.1

  1. 多任务协程:
  1. import asyncio
  2. import requests
  3. import threading
  4. url = 'http://www.cgfantuan.com'
  5. async def request():
  6. status = requests.get(url)
  7. print("Current thread::",threading.current_thread().getName())
  8. return status
  9. tasks = [asyncio.ensure_future(request()) for _ in range(5)]
  10. print("Task::",tasks)
  11. loop = asyncio.get_event_loop()
  12. loop.run_until_complete(asyncio.wait(tasks))
  13. for task in tasks:
  14. print("Task result::",task.result())

reslut:

  1. Task:: [<Task pending name='Task-1' coro=<request() running at test02.py:6>>, <Task pending name='Task-2' coro=<request() running at test02.py:6>>, <Task pending name='Task-3' coro=<request() running at test02.py:6>>, <Task pending name='Task-4' coro=<request() running at test02.py:6>>, <Task pending name='Task-5' coro=<request() running attest02.py:6>>]
  2. Current thread:: MainThread
  3. Current thread:: MainThread
  4. Current thread:: MainThread
  5. Current thread:: MainThread
  6. Current thread:: MainThread
  7. Task result:: <Response [200]>
  8. Task result:: <Response [200]>
  9. Task result:: <Response [200]>
  10. Task result:: <Response [200]>
  11. Task result:: <Response [200]>

不管不顾,一顿request,空了慢慢接收response.

 

eg.2

flask,django,xmlrpc都有以下功能(搬运ing)

  1. # Flask server
  2. from flask import Flask
  3. import time
  4. app = Flask(__name__)
  5. @app.route('/')
  6. def index():
  7. time.sleep(3)
  8. return 'Hello!'
  9. if __name__ == '__main__':
  10. app.run(threaded=True)
  1. import asyncio
  2. import aiohttp
  3. import time
  4. start = time.time()
  5. async def get(url):
  6. session = aiohttp.ClientSession()
  7. response = await session.get(url)
  8. result = await response.text()
  9. await session.close()
  10. return result
  11. async def request():
  12. url = 'http://127.0.0.1:5000'
  13. print('Waiting for', url)
  14. result = await get(url)
  15. print('Get response from', url, 'Result:', result)
  16. tasks = [asyncio.ensure_future(request()) for _ in range(5)]
  17. loop = asyncio.get_event_loop()
  18. loop.run_until_complete(asyncio.wait(tasks))
  19. end = time.time()
  20. print('Cost time:', end - start)

result:

  1. Waiting for http://127.0.0.1:5000
  2. Waiting for http://127.0.0.1:5000
  3. Waiting for http://127.0.0.1:5000
  4. Waiting for http://127.0.0.1:5000
  5. Waiting for http://127.0.0.1:5000
  6. Get response from http://127.0.0.1:5000 Result: Hello!
  7. Get response from http://127.0.0.1:5000 Result: Hello!
  8. Get response from http://127.0.0.1:5000 Result: Hello!
  9. Get response from http://127.0.0.1:5000 Result: Hello!
  10. Get response from http://127.0.0.1:5000 Result: Hello!
  11. Cost time: 3.0132627487182617

执行过程:

  1. 按顺序执行task
  2. 遇到await,挂起当前任务
  3. 执行其他task,jump step2,无其他task,jump step4
  4. 桉顺序执行挂起任务

eg.3

  1. # 单进程
  2. import requests
  3. import time
  4. start = time.time()
  5. def request():
  6. url = 'http://127.0.0.1:5000'
  7. print('Waiting for', url)
  8. result = requests.get(url).text
  9. print('Get response from', url, 'Result:', result)
  10. for _ in range(100):
  11. request()
  12. end = time.time()
  13. print('Cost time:', end - start)
  1. # 多进程 + 协程
  2. import asyncio
  3. import aiohttp
  4. import time
  5. from aiomultiprocess import Pool
  6. start = time.time()
  7. async def get(url):
  8. session = aiohttp.ClientSession()
  9. response = await session.get(url)
  10. result = await response.text()
  11. await session.close()
  12. return result
  13. ## !!! 有问题,待调试
  14. async def request():
  15. url = 'http://127.0.0.1:5000'
  16. urls = [url for _ in range(5)]
  17. async with Pool() as pool:
  18. result = await pool.map(get, urls)
  19. return result
  20. coroutine = request()
  21. task = asyncio.ensure_future(coroutine)
  22. loop = asyncio.get_event_loop()
  23. loop.run_until_complete(task)
  24. end = time.time()
  25. print('Cost time:', end - start)

参考4 https://segmentfault.com/a/1190000009769387 使用close和throw方法控制协程

参考5 https://github.com/gmarull/asyncqt 这个是pyqt的异步协程,非常好。其实就是把Qt的eventloop给替换了。所以,

  1. QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
  2. QCoreApplication.processEvents()

QEventLoop,QRunnable会不会就类似于和携程一样原理的东东(我觉得QRunnable就是携程,没证实,逃)

想法

在项目里面,我这边用了pyqt做前端,所以需要ui和业务分离,而且业务还有调取服务器数据、本地缓存数据,io处理的需求,所以就考虑到需要用到协程。但是!但是!如果是重(四声)计算的task的话,虽然不会卡界面,但是,也会出现问题,毕竟是eventloop,会把task挂起来,所以像GUI界面,大部分不建议用协程。如果你是做网页爬虫的话,那就另当别论了。

转载请注明:XAMPP中文组官网 » Python Coroutine Async_协程、异步实例代码

您必须 登录 才能发表评论!