本文是写给 JavaScript 程序员的 Python 教程。

Python 的异步编程,其他人可能觉得很难,但是 JavaScript 程序员应该特别容易理解,因为两者的概念和语法类似。JavaScript 的异步模型更简单直观,很适合作为学习 Python 异步的基础。

本文解释 Python 的异步模块 asyncio 的概念和基本用法,并且演示如何通过 Python 脚本操作无头浏览器 pyppeteer 。

一、Python 异步编程的由来

历史上,Python 并不支持专门的异步编程语法,因为不需要。

有了多线程(threading)和多进程(multiprocessing),就没必要一定支持异步了。如果一个线程(或进程)阻塞,新建其他线程(或进程)就可以了,程序不会卡死。

但是,多线程有"线程竞争"的问题,处理起来很复杂,还涉及加锁。对于简单的异步任务来说(比如与网页互动),写起来很麻烦。

Python 3.4 引入了 asyncio 模块,增加了异步编程,跟 JavaScript 的async/await 极为类似,大大方便了异步任务的处理。它受到了开发者的欢迎,成为从 Python 2 升级到 Python 3 的主要理由之一。

二、asyncio 的设计

asyncio 模块最大特点就是,只存在一个线程,跟 JavaScript 一样。

由于只有一个线程,就不可能多个任务同时运行。asyncio 是"多任务合作"模式(cooperative multitasking),允许异步任务交出执行权给其他任务,等到其他任务完成,再收回执行权继续往下执行,这跟 JavaScript 也是一样的。

由于代码的执行权在多个任务之间交换,所以看上去好像多个任务同时运行,其实底层只有一个线程,多个任务分享运行时间。

表面上,这是一个不合理的设计,明明有多线程多进程的能力,为什么放着多余的 CPU 核心不用,而只用一个线程呢?但是就像前面说的,单线程简化了很多问题,使得代码逻辑变得简单,写法符合直觉。

asyncio 模块在单线程上启动一个事件循环(event loop),时刻监听新进入循环的事件,加以处理,并不断重复这个过程,直到异步任务结束。事件循环的内部机制,可以参考 JavaScript 的模型,两者是一样的。

三、asyncio API

下面介绍 asyncio 模块最主要的几个API。注意,必须使用 Python 3.7 或更高版本,早期的语法已经变了。

第一步,import 加载 asyncio 模块。

import asyncio

第二步,函数前面加上 async 关键字,就变成了 async 函数。这种函数最大特点是执行可以暂停,交出执行权。

async def main():

第三步,在 async 函数内部的异步任务前面,加上await命令。

await asyncio.sleep(1)

上面代码中,asyncio.sleep(1) 方法可以生成一个异步任务,休眠1秒钟然后结束。

执行引擎遇到await命令,就会在异步任务开始执行之后,暂停当前 async 函数的执行,把执行权交给其他任务。等到异步任务结束,再把执行权交回 async 函数,继续往下执行。

第四步,async.run() 方法加载 async 函数,启动事件循环。

asyncio.run(main())

上面代码中,asyncio.run() 在事件循环上监听 async 函数main的执行。等到 main 执行完了,事件循环才会终止。

四、async 函数的示例

下面是 async 函数的例子,新建一个脚本async.py,代码如下。

#!/usr/bin/env python3

# async.py

importasyncio

async defcount():

print("One")

await asyncio.sleep(1)

print("Two")

async defmain():

await asyncio.gather(count(), count(), count())

asyncio.run(main())

上面脚本中,在 async 函数main的里面,asyncio.gather() 方法将多个异步任务(三个 count())包装成一个新的异步任务,必须等到内部的多个异步任务都执行结束,这个新的异步任务才会结束。

脚本的运行结果如下。

$ python3 async.py

One

One

One

Two

Two

Two

上面运行结果的原因是,三个 count() 依次执行,打印完 One,就休眠1秒钟,把执行权交给下一个 count(),所以先连续打印出三个 One。等到1秒钟休眠结束,执行权重新交回第一个 count(),开始执行 await 命令下一行的语句,所以会接着打印出三个Two。脚本总的运行时间是1秒。

作为对比,下面是这个例子的同步版本 sync.py。

#!/usr/bin/env python3

# sync.py

importtime

defcount():

print("One")

time.sleep(1)

print("Two")

defmain():

for_inrange(3):

count()

main()

上面脚本的运行结果如下。

$ python3 sync.py

One

Two

One

Two

One

Two

上面运行结果的原因是,三个 count() 都是同步执行,必须等到前一个执行完,才能执行后一个。脚本总的运行时间是3秒。

五、实例:pyppeteer 模块

最后是一个异步编程的真实例子:操作无头浏览器。异步编程对代码的简化,在这个例子体现得淋漓尽致。

我们需要用到 pyppeteer 模块,它是无头浏览器 Puppeteer 的 Python 移植,API 跟 JavaScript 版本基本一致。下面是安装命令。

$ python3 -m pip install pyppeteer

然后,写一个网页截图脚本screenshot.py。

#!/usr/bin/env python3

# screenshot.py

importasyncio

frompyppeteerimportlaunch

async defmain():

browser = await launch()

page = await browser.newPage()

await page.goto('http://example.com')

await page.screenshot({'path':'example.png'})

await browser.close()

asyncio.run(main())

上面代码中,启动浏览器(launch)、打开新 Tab(newPage())、访问网址(page.goto())、截图(page.screenshot())、关闭浏览器(browser.close()),这一系列操作都是异步任务,使用 await 命令写起来非常自然简单。

执行这个脚本,当前目录下就会生成截图文件 example.png。

$ python3 screenshot.py

如果脚本执行时报错 No usable sandbox!,可以参考这里。另外,第一次执行这个脚本,会下载安装 Puppeteer,可能需要等待较长时间,但是此后的执行就会很快。

Pyppeteer 的官网还有其他实例,比如向网页注入 JavaScript 代码,大家可以自己试玩。

六、参考链接

python2异步编程_Python 异步编程入门相关推荐

  1. python2异步编程_python异步编程 (转载)

    转自:https://zhuanlan.zhihu.com/p/27258289 本文将会讲述Python 3.5之后出现的async/await的使用方法,以及它们的一些使用目的,如果错误,欢迎指正 ...

  2. python socket编程_Python Socket编程实现网络编程

    对于有经验的开发人员来说,掌握的编程语言应该是不少的.在这些编程语言中,网络编程的应用时必不可少的.其中Python也是这样的编程语言.我们今天将会在这里为大家详细介绍一下Python Socket编 ...

  3. python2异步编程_python异步编程入门

    这几天看代码,总是会接触到很多异步编程,之前只想着实现功能,从来没考虑过代码的运行快慢问题,故学习一番. 从0到1,了解python异步编程的演进 1.urllib与requests爬虫 reques ...

  4. python的异步网络编程_python异步网络编程怎么使socket关闭之后立即执行一段代码?...

    import socket from _socket import getdefaulttimeout class MySocket(socket.socket): """ ...

  5. python事件驱动编程_Python事件驱动编程

    事件驱动的编程侧重于事件.最终,程序的流程取决于事件.到目前为止,我们处理顺序或并行执行模型,但具有事件驱动编程概念的模型称为异步模型.事件驱动的编程取决于始终侦听新传入事件的事件循环.事件驱动编程的 ...

  6. python高并发编程_python 并发编程

    一 背景知识 一 操作系统的发展 没有操作系统----穿孔卡片(对应程序和数据) 特点:手工慢与计算机高速形成极大矛盾. (1)用户独占全机. (2)CPU等待手工操作. 批处理系统---磁带存储 控 ...

  7. python 窗体编程_python窗体编程

    广告关闭 云服务器1核2G首年99年,还有多款热门云产品满足您的上云需求 python里的图形化界面(gui)模块主要有tkinter(python自带).pyqt.wxpython,我们这节主要讲解 ...

  8. python执行cmd命令行异步执行_Python 异步调用命令行工具

    当你在自己的 Python 程序中采用了基于事件循环的异步编程方法之后,你就会发现自己不自觉地被其牢牢吸引住,并不是说这一方法多么棒,而是因为你不得不想办法保证程序中的任意环节都不能是阻塞的! 例如当 ...

  9. python高并发编程_Python——并发编程

    开始说并发编程之前,最好有一定的底层知识积累,这里我把需要的知识总结了一下,如果看下面的有不理解的可以看一下:https://www.cnblogs.com/kuxingseng95/p/941820 ...

最新文章

  1. java.lang.NoSuchMethodError: No virtual method placeholder(I)Lcom/bumptech/
  2. swift 通知中心 进入后台多久会通知用户关闭此功能
  3. 禁毒学、油画、乌尔都语……字节跳动程序员的专业有多奇特丨技术同学大数据报告...
  4. oracle 32位和64位的问题
  5. 最近安装了win2008R2,界面比win2003友好多了
  6. go语言游戏编程初识--`Ebiten`
  7. Java整数类的compareTo()方法和示例
  8. win7右键计算机管理参数错误,win7纯净版虚拟磁盘管理器参数错误怎么解决?
  9. js保留两位小数的函数_如何在Excel中使用ROUND系列函数
  10. 35岁以后,被社会无情抛弃,放下面子赚钱
  11. Web服务器程序解释请求消息并作出响应
  12. WINDOW10初步使用
  13. HeadFirst设计模式-命令模式
  14. protues8.9安装【硬件课设】
  15. qq能上网浏览器不可以
  16. [HNOI2007] 紧急疏散EVACUATE
  17. EOS智能合约开发系列(四)
  18. 格子玻尔兹曼机(Lattice Boltzmann Method)系列3:LBM在不可压缩流动下的边界条件算法
  19. TrestZone入门解读
  20. 计算机网络-自顶向下笔记-应用层-P2P应用

热门文章

  1. 本科、硕士、博士的区别(终极版,太形象了!)
  2. android注册界面高级,Android用户注册界面简单设计
  3. mysql数据库sql审核_Inception SQL审核注解
  4. 山师计算机试题答案,山师计算机应用技术试题及答案
  5. python代码覆盖率怎么统计的_Python代码覆盖率统计工具coverage.py用法详解
  6. 电子科技大学20春《c语言》在线作业1,[电子科技大学]20秋《C语言》在线作业123(答案)...
  7. python列表索引负数_python – 如何检查列表索引是否存在?
  8. Excel VBA(宏):添加宏
  9. angular directive自定义指令
  10. 设计模式 ( 十七 ):Observer 观察者模式 -- 行为型