asyncio异步IO--同步原语
asyncio同步原语与线程(threading)模块同步原语基本类似,但有两点重要区别:
- asyncio同步原语
非线程安全
,因此不应被用作系统线程同步(可以使用threading
代替); - asyncio同步原语不允许使用
timeout
参数;可以使用asyncio.wait_for()
方法执行有超时设置的操作。
asyncio有以下5个基本的同步原语:
- Lock
- Event
- Condition
- Semaphore
- BoundedSemaphore
Lock
- class asyncio.Lock(*,loop=None)
- 为asyncio任务提供一个
互斥锁
。非线程安全。 - asyncio锁可以用来保证对共享资源的独占访问。
- asyncio锁的首选用法是同
async with
语句一起使用:lock = asyncio.Lock()
# ... later
async with lock:
# 访问共享资源
此代码段和以下代码是等价的:
lock = asyncio.Lock() # ... later
await lock.acquire()
try:
# 访问共享资源
finally:
lock.release()
- coroutine acquire()
- 获取asyncio同步锁。
- 该方法等待
锁
的状态变为unlocked
,之后设置其为locked
,并返回True
。
- release()
- 释放asyncio同步锁。
- 如果
锁
的状态是locked
,则将其重置为unlocked
并返回。 - 如果
锁
的状态是unlocked
,会引发RuntimeError
异常。
- locked()
- 如果
锁
的状态是locked
,则返回True
。
- 如果
- 为asyncio任务提供一个
Event
- class asyncio.Event(*,loop=None)
- 事件对象,非线程安全。
- 用于向asyncio任务通知某些事件已发生。
- 事件对象用于管理
内部标志
。此标志可以通过set()
方法设置为True
,或通过clear()
方法复位为False
。wait()
方法在该标志设置为True
前一直保持阻塞。初始状态下,该标志为False
。 - 例如:
async def waiter(event):
print('waiting for it ...')
await event.wait()
print('... got it!') async def main():
# Create an Event object.
event = asyncio.Event() # Spawn a Task to wait until 'event' is set.
waiter_task = asyncio.create_task(waiter(event)) # Sleep for 1 second and set the event.
await asyncio.sleep(1)
event.set() # Wait until the waiter task is finished.
await waiter_task asyncio.run(main())
- coroutine wait()
- 等待事件
内部标志
被设置为True
。 - 如果事件的内部
内部标志
已设置,则立即返回True
。否则,一直阻塞,直到另外的任务调用set()
。
- 等待事件
- set()
- 设置事件
内部标志
为True
。 - 所有等待事件的任务将会立即被触发。
- 设置事件
- clear()
- 清除事件
内部标志
(即设置为False
)。 - 等待事件的任务将会阻塞,直到
set()
方法被再次调用。
- 清除事件
- is_set()
- 如果事件
内部标志
被设置为True
,则返回True
。
- 如果事件
Condition
- class asyncio.Condition(lock=None,*,loop=None)
- 条件对象,非线程安全。
- 异步条件原语用于在某些事件发生后,获得共享资源的独占访问权限。
- 本质上,条件对象结合了事件和锁的功能。可以让多个Condition对象共享一个Lock,这允许在对共享资源的特定状态感兴趣的不同任务之间协调对共享资源的独占访问。
- 可选参数
lock
必须为Lock
对象或None
。如果为None
,会自动创建一个Lock
对象。 - 使用条件对象的首选方法是
async with
方式:cond = asyncio.Condition() # ... later
async with cond:
await cond.wait()
等价于:
cond = asyncio.Condition() # ... later
await lock.acquire()
try:
await cond.wait()
finally:
lock.release()
- coroutine acquire()
- 获取底层锁。
- 该方法一直等待,直到底层锁处于未锁定状态,然后设置其为锁定状态,并且返回
True
。
- notify(n=1)
- 唤醒至多
n
个等待条件的任务。如果没有正在等待的任务,则该方法无操作。 - 在调用该方法之前,必须先调用
acquire()
获取锁,并在调用该方法之后释放锁。如果在锁为锁定的情况下调用此方法,会引发RuntimeError
异常。
- 唤醒至多
- locked()
- 如果底层锁已获取,则返回
True
。
- 如果底层锁已获取,则返回
- notify_all()
- 唤醒所有正在等待该条件的任务。
- 该方法与
notify()
类似,区别只在它会唤醒所有正在等待的任务。 - 在调用该方法前,必须首先获取底层锁,并在执行完该方法后释放锁。如果在底层锁未锁定的情况下执行该方法,会引发
RuntimeError
异常。
- release()
- 释放底层锁。
- 在未锁定的锁上调用时,会引发
RuntimeError
异常。
- coroutine wait()
- 等待通知。
- 如果调用此方法的任务没有获取到锁,则引发
RuntimeError
异常。 - 此方法释放底层锁,然后保持阻塞,直至被
notify()
或notify_all()
唤醒。被唤醒之后,条件对象重新申请锁,该方法返回True
。
- coroutine wait_for(predicate)
- 等待
predicate
变为True
。 predicate
必须可调用,它的执行结果会被解释为布尔值,并作为最终结果返回。
- 等待
Semaphore
- class asyncio.Semaphore(value=1,*,loop=None)
- 信号量(Semaphore)对象。非线程安全。
- 信号量用于管理一个内部计数器,此计数器逢
acquire()
递减,逢release()
递增。计数器的值不能小于0
,如果acquire()
被调用时计数器为0
,则阻塞,直到某一任务调用release()
。 value
为可选参数,用于设定内部计数器的初始值。如果给定的值小于0,则引发ValueError
异常。- 使用
信号量
的最佳方法是async with
声明:sem = asyncio.Semaphore(10) # ... later
async with sem:
# work with shared resource
等价于:
sem = asyncio.Semaphore(10) # ... later
await sem.acquire()
try:
# work with shared resource
finally:
sem.release()
- coroutine acquire()
- 申请一个信号量
- 如果内部计数器的值大于0,则减1并立即返回
True
。如果内部计数器的值为0,则等待release()
被调用,然后返回True
。
- locked()
- 如果信号量不能被立即申请,则返回
True
。
- 如果信号量不能被立即申请,则返回
- release()
- 释放信号量,内部计数器加1。
- 与
BoundedSemaphore
不同,Semaphore
允许release()
的调用次数大于acquire()
的调用次数。
BoundedSemaphore
- class asyncio.BoundedSemaphore(value=1,*,loop=None)
- 有界信号量,非线程安全。
- 有界信号量是一种特殊的信号量——如果
release()
后内部计数器的值大于初始值,则引发ValueError
异常。
从python3.7开始:通过await lock
、yield from lock
或通过声明with await lock
、with(yield from lock)
获取锁的用法被废弃。可使用async with lock
代替。
asyncio异步IO--同步原语的更多相关文章
- 【Python学习之九】asyncio—异步IO
asyncio 这是python3.4引入的标准库,直接内置对异步IO的支持.asyncio的编程模型就是一个消息循环.从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程 ...
- asyncio异步IO——Streams详解
前言 本文翻译自python3.7官方文档--asyncio-stream,译者马鸣谦,邮箱 1612557569@qq.com.转载请注明出处. 数据流(Streams) 数据流(Streams)是 ...
- 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. ...
- 爬虫之多线程 多进程 自定义异步IO框架
什么是进程? 进程是程序运行的实例,是系统进行资源分配和调度的一个独立单位,它包括独立的地址空间,资源以及1个或多个线程. 什么是线程? 线程可以看成是轻量级的进程,是CPU调度和分派的基本单位. 进 ...
- 2020.11.2 异步IO 协程
异步IO 同步IO在一个线程中,CPU执行代码的速度极快,然而,一旦遇到IO操作,如读写文件.发送网络数据时,就需要等待IO操作完成,才能继续进行下一步操作. 在IO操作的过程中,当前线程被挂起,而其 ...
- 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制
转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...
- Python并发编程之初识异步IO框架:asyncio 上篇(九)
大家好,并发编程 进入第九篇. 通过前两节的铺垫(关于协程的使用),今天我们终于可以来介绍我们整个系列的重点 -- asyncio. asyncio是Python 3.4版本引入的标准库,直接内置了对 ...
- (转)Python黑魔法 --- 异步IO( asyncio) 协程
转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...
- python中同步、多线程、异步IO、多线程对IO密集型的影响
目录 1.常见并发类型 2.同步版本 3.多线程 4.异步IO 5.多进程 6.总结 1.常见并发类型 I/ O密集型: 蓝色框表示程序执行工作的时间,红色框表示等待I/O操作完成的时间.此图没有按比 ...
随机推荐
- [Swift]LeetCode75. 颜色分类 | Sort Colors
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the ...
- Jedis与Luttuce区别
如果你在网上搜索Redis 的Java客户端,你会发现,大多数文献介绍的都是 Jedis. 不可否认,Jedis是一个优秀的基于Java语言的Redis客户端. 但是,其不足也很明显:Jedis在实现 ...
- Git的使用--如何将本地项目上传到Github(三种简单、方便的方法)
一.第一种方法: 1.首先你需要一个github账号,所以还没有的话先去注册吧! https://github.com/ 我们使用git需要先安装git工具,这里给出下载地址,下载后一路(傻瓜式安装) ...
- TLS 1.3 VS TLS 1.2,让你明白 TLS 1.3 的强大
HTTPS 加密时代已经来临,近两年,Google.Baidu.Facebook 等互联网巨头,不谋而合地开始大力推行 HTTPS, 2018 年 7 月 25 日,Chrome 68 上线,所有 H ...
- SpringCloud(7)---网关概念、Zuul项目搭建
SpringCloud(7)---网关概念.Zuul项目搭建 一.网关概念 1.什么是路由网关 网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求.鉴权.监控. ...
- 【从零开始自制CPU之学习篇02】555定时器
555定时器是一种集成电路芯片,常被用于定时器.脉冲产生器和震荡电路.在CPU制作中作为pc(程序计数器)的主要组成部分.以下是我购买的NE555实拍图: NE555的针脚示意图: 555定时器各针脚 ...
- Python爬虫入门教程 5-100 27270图片爬取
27270图片----获取待爬取页面 今天继续爬取一个网站,http://www.27270.com/ent/meinvtupian/ 这个网站具备反爬,so我们下载的代码有些地方处理的也不是很到位, ...
- C语言实现顺序栈的初始化&进栈&出栈&读取栈顶元素
/*顺序表实现栈的一系列操作*/ #include<stdio.h> #include<stdlib.h> #define Stack_Size 50 //设栈中元素个数为50 ...
- Linux基础命令第二天
1,修改命令提示符 修改Linux命令行显示,需要用到PS1变量,PS1是Linux终端用户的一个环境变量.在终端输入命令:set,就会找到PS1变量,然后给PS1重新赋值,就会得到对应的样式. 默认 ...
- 第31章 日志 - Identity Server 4 中文文档(v1.0.0)
IdentityServer使用ASP.NET Core提供的标准日志记录工具.Microsoft文档有一个很好的介绍和内置日志记录提供程序的描述. 我们大致遵循Microsoft使用日志级别的指导原 ...