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语句一起使用:
      1. lock = asyncio.Lock()
      2. # ... later
      3. async with lock:
      4. # 访问共享资源

      此代码段和以下代码是等价的:

      1. lock = asyncio.Lock()
      2. # ... later
      3. await lock.acquire()
      4. try:
      5. # 访问共享资源
      6. finally:
      7. lock.release()
    • coroutine acquire()
      • 获取asyncio同步锁。
      • 该方法等待的状态变为unlocked,之后设置其为locked,并返回True
    • release()
      • 释放asyncio同步锁。
      • 如果的状态是locked,则将其重置为unlocked并返回。
      • 如果的状态是unlocked,会引发RuntimeError异常。
    • locked()
      • 如果的状态是locked,则返回True

Event

  • class asyncio.Event(*,loop=None)

    • 事件对象,非线程安全。
    • 用于向asyncio任务通知某些事件已发生。
    • 事件对象用于管理内部标志。此标志可以通过set()方法设置为True,或通过clear()方法复位为Falsewait()方法在该标志设置为True前一直保持阻塞。初始状态下,该标志为False
    • 例如:
      1. async def waiter(event):
      2. print('waiting for it ...')
      3. await event.wait()
      4. print('... got it!')
      5. async def main():
      6. # Create an Event object.
      7. event = asyncio.Event()
      8. # Spawn a Task to wait until 'event' is set.
      9. waiter_task = asyncio.create_task(waiter(event))
      10. # Sleep for 1 second and set the event.
      11. await asyncio.sleep(1)
      12. event.set()
      13. # Wait until the waiter task is finished.
      14. await waiter_task
      15. 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方式:
      1. cond = asyncio.Condition()
      2. # ... later
      3. async with cond:
      4. await cond.wait()

      等价于:

      1. cond = asyncio.Condition()
      2. # ... later
      3. await lock.acquire()
      4. try:
      5. await cond.wait()
      6. finally:
      7. 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声明:
      1. sem = asyncio.Semaphore(10)
      2. # ... later
      3. async with sem:
      4. # work with shared resource

      等价于:

      1. sem = asyncio.Semaphore(10)
      2. # ... later
      3. await sem.acquire()
      4. try:
      5. # work with shared resource
      6. finally:
      7. 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 lockyield from lock或通过声明with await lockwith(yield from lock)获取锁的用法被废弃。可使用async with lock代替。

asyncio异步IO--同步原语的更多相关文章

  1. 【Python学习之九】asyncio—异步IO

    asyncio 这是python3.4引入的标准库,直接内置对异步IO的支持.asyncio的编程模型就是一个消息循环.从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程 ...

  2. asyncio异步IO——Streams详解

    前言 本文翻译自python3.7官方文档--asyncio-stream,译者马鸣谦,邮箱 1612557569@qq.com.转载请注明出处. 数据流(Streams) 数据流(Streams)是 ...

  3. 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

    POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. ...

  4. 爬虫之多线程 多进程 自定义异步IO框架

    什么是进程? 进程是程序运行的实例,是系统进行资源分配和调度的一个独立单位,它包括独立的地址空间,资源以及1个或多个线程. 什么是线程? 线程可以看成是轻量级的进程,是CPU调度和分派的基本单位. 进 ...

  5. 2020.11.2 异步IO 协程

    异步IO 同步IO在一个线程中,CPU执行代码的速度极快,然而,一旦遇到IO操作,如读写文件.发送网络数据时,就需要等待IO操作完成,才能继续进行下一步操作. 在IO操作的过程中,当前线程被挂起,而其 ...

  6. 【译】深入理解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% ...

  7. Python并发编程之初识异步IO框架:asyncio 上篇(九)

    大家好,并发编程 进入第九篇. 通过前两节的铺垫(关于协程的使用),今天我们终于可以来介绍我们整个系列的重点 -- asyncio. asyncio是Python 3.4版本引入的标准库,直接内置了对 ...

  8. (转)Python黑魔法 --- 异步IO( asyncio) 协程

    转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...

  9. python中同步、多线程、异步IO、多线程对IO密集型的影响

    目录 1.常见并发类型 2.同步版本 3.多线程 4.异步IO 5.多进程 6.总结 1.常见并发类型 I/ O密集型: 蓝色框表示程序执行工作的时间,红色框表示等待I/O操作完成的时间.此图没有按比 ...

随机推荐

  1. [Swift]LeetCode397. 整数替换 | Integer Replacement

    Given a positive integer n and you can do operations as follow: If n is even, replace n with n/2. If ...

  2. [Swift]LeetCode1008. 先序遍历构造二叉树 | Construct Binary Search Tree from Preorder Traversal

    Return the root node of a binary search tree that matches the given preorder traversal. (Recall that ...

  3. Vue入门手册整理

    目录 第一章.环境搭建 第二章.目录结构 第三章.Vue调试 第四章.定义页面 附录资料 第一章.环境搭建 1.1.准备: npm: 6.9.0 (npm > 3.0) node: v10.15 ...

  4. springboot中实现多数据源

    springboot中实现多数据源 1.什么场景需要多数据源 业务读写分离 业务分库 业务功能模块拆分多库 2.常见的多数据源的方案 按照数据源分别把mapper和entity放到不同的package ...

  5. TCP的三次握手与四次挥手(个人总结)

    序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生:给字节编上序号后,就给每一个报文段指派一个序号:序列号seq就是这个报文 ...

  6. 面试题:合并2个有序数组(leetcode88)

    给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素数量分别为 m 和 n. ...

  7. 【java设计模式】(5)---装饰者模式(案例解析)

    设计模式之装饰者模式 一.概念 1.什么是装饰者模式 装饰模式是在不使用继承和不改变原类文件的情况下,动态的扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.    这一个解释 ...

  8. 从0打卡leetcode之day 3 -- 最大子序列和

    前言 就有要把leetcode的题刷完,每天一道题,每天进步一点点 从零打卡leetcode之day 3 题目描述: 给定一个int类型的数组,求最大子序列的和. 也就是说,从这个数组中截取一个子数组 ...

  9. Spring Boot分布式系统实践【扩展1】shiro+redis实现session共享、simplesession反序列化失败的问题定位及反思改进

    前言 调试之前请先关闭Favicon配置 spring:     favicon:       enabled: false 不然会发现有2个请求(如果用nginx+ 浏览器调试的话) 序列化工具类[ ...

  10. List-ArrayList集合基础增强底层源码分析

    List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...