前言
为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读。
请注意,async和await是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
把@asyncio.rotoutine替换为async; 把yield from替换为await。async/await 是一种异步变成方法,还有两种你可能听过,
1. 回调
2. Promise
(写过 JavaScript 的肯定很熟悉了)
异步意味着任务不会阻塞,比如,如果我要下载一个比较忙的网络资源,我的程序不需要一直等待下载完成,它可以在等待下载时继续做其他事情。这与并行执行多个操作不同。以下伪代码比较容易理解:
# 慢方法page = get_page_sync('some_page')# 会阻塞整个程序的运行print(page)
有两种方法可以改善上述的情况
(一)首先,让我们试试使用线程。通过使用线程,我们可以将 get_page_sync 调用放到单独的线程去执行,这样主线程 就可以继续执行其他操作。
# 将慢方法放到单独的线程执行t = threading.thread( target = get_page_sync('some_page',args=('some_page',)))t.run()# 在线程运行时执行其他操作do_something_else()# 等待线程完执行成t.join()
线程有几个优缺点,主要的缺点是:
1. 必须在改变共享数据前锁定共享数据
2. 只能通过传递给主线程消息来处理线程内的异常
(二)现在我们试试第二种中的 async/await,Python3.5 开始支持的 async/await 方式,与第一种(线程)之间的主要区别在于,后者是操作系统内核执行上下文切换,而前者中我们自己控制。(上下文切换即,当多个线程正在运行时,内核可能停止当前进程,使其进入休眠状态,并选择不同的线程继续执行。这被称作抢占式多任务处理【Preemption】)
当我们自己控制时,它被称作非抢占式或合作型多任务式,因为是我们自己处理上下文切换,所以我们需要一个调度程序,也叫做『事件循环』。此事件循环只循环遍历等待中的调度,并运行它的所有事件。每当我们产生操作时,当前任务会被添加到队列中,且第一个任务(优先级而非顺序)从队列中弹出并开始执行。例如,可以通过以下方式更改上述伪代码:
async def print_page(): page = await get_page_sync('some_page') print(page)
当我们触发上面的语句时,get_page_async 方法将非阻塞的获取 some_page 还有 yield 句柄,这意味着我们的 print_page 函数将控制时间循环 ,并且时间循环可以继续执行其他曹组,知道我们得到返回的响应。
新闻热点
疑难解答