并发编程与异步IO-Python

并发编程与异步IO

基本概念:并发,并行,同步,异步,阻塞,非阻塞

并发:一个时间段内,有几个程序在同一个 CPU 上运行,但是任意时刻只有一个程序在 CPU 上运行。
并行:在任意时刻点上,有多个程序同时运行在**多个 CPU **上。如果 CPU 有个四颗,那么并行最多只有四个。
基于以上,我们都说高并发,不说高并行。
同步:代码调用 IO 操作时,必须等待 IO 操作完成才返回的调用方式。
异步:指代码调用 IO 操作时,不必等 IO 操作完成就返回的调用方式。
阻塞:指调用函数时,当前线程被挂起。
非阻塞:指调用函数时,当前线程不会被挂起,而是立即返回。
阻塞和非阻塞是说的函数调用的一种机制。

多线程与多进程

CPython中,多线程thread常用来处理io密集型的操作,因为GIL的原因无法利用多核优势,如果是计算密集型的操作需要多进程multiprocess,多线程的优势在与线程之间数据共享,也真是因为数据共享所以多线程会抢占共享资源这就需要这种东西,多进程不会出现这种情况因为数据不共享嘛(相当于多个python解释器在运行),但是这也有问题,多进程通信就是一个难题.

线程模块:Threading

进程模块:Multiprocessing

懒人包:Concurrent

异步框架 asyncio

异步框架的发展由来: yield-->yield from -->gevent/greenlet-->asyncio,asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

基本概念:

  • event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数(协程)注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
  • coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
  • future 对象: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
  • task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。Task 对象是 Future 的子类,它将 coroutine 和 Future 联系在一起,将 coroutine 封装成一个 Future 对象。
  • async/await 关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。其作用在一定程度上类似于yield。

asyncio协程是如何工作的

  • 1.创建协程对象coroutine,创建事件循环event_loop
  • 2.将协程转为task任务,之后可以选择添加回调函数
  • 3.将task任务扔进事件循环对象中触发
  • 4.获取任务结果

单任务携程

单任务的携程是没有什么意义的这里主要是为了了解asyncio协程整体是如何工作的

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
import asyncio import time #1创建事件循环event_loop loop = asyncio.get_event_loop() #2创建携程函数 async def func1(): await asyncio.sleep(1) return '1finished' async def func2(): await asyncio.sleep(3) return '2finished' #3 携程函数转成携程对象 coroutine = func1() #4 携程对象转成task对象 task = loop.create_task(coroutine) #5 给task添加回调函数 def _callback(task): print(f'回调函数获得结果:{task.result()}') task.add_done_callback(_callback) #6 启动事件循环 loop.run_until_complete(task) #7获得任务结果 print(task.result())

多任务携程并发实现

1可以用另一个函数把携程函数整合起来,并发的逻辑在整合函数中实现,但是如果方法不对可能无法实现并发

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
import asyncio import time #1创建事件循环event_loop loop = asyncio.get_event_loop() #2创建携程函数 async def func1(): await asyncio.sleep(1) return '1finished' async def func2(): await asyncio.sleep(3) return '2finished' #不能并发的的例子 async def test_error(): star = time.time() coroutine1 = func1() coroutine2 = func2() await loop.create_task(coroutine1) await loop.create_task(coroutine2) print('all done',time.time()-star) if __name__ == '__main__': loop.run_until_complete(test_error()) #这样写就可以并发了 async def test1(): star = time.time() coroutine1 = func1() coroutine2 = func2() task1 = loop.create_task(coroutine1) task2 = loop.create_task(coroutine2) await task1 await task2 print('all done',time.time()-star) if __name__ == '__main__': loop.run_until_complete(test1()) #通常并发的用法,使用asyncio.wait或者asyncio.gather async def test2(): star = time.time() coroutine1 = func1() coroutine2 = func2() task1 = loop.create_task(coroutine1) task2 = loop.create_task(coroutine2) tasks = [task1,task2] result = await asyncio.gather(*tasks) print(task1.result()) print('all done',time.time()-star) if __name__ == '__main__': loop.run_until_complete(test2()) async def test3(): star = time.time() coroutine1 = func1() coroutine2 = func2() task1 = loop.create_task(coroutine1) task2 = loop.create_task(coroutine2) tasks = [task1,task2] await asyncio.wait(tasks) print(task1.result()) print('all done',time.time()-star) if __name__ == '__main__': loop.run_until_complete(test3()) #多任务携程回调函数的使用,依次给task添加回调函数 def callback(task): print(f'回调函数触发:{task.result()}') async def test4(): star = time.time() coroutine1 = func1() coroutine2 = func2() task1 = loop.create_task(coroutine1) task2 = loop.create_task(coroutine2) tasks = [task1,task2] for task in tasks: task.add_done_callback(callback) await asyncio.gather(*tasks) print('all done',time.time()-star) if __name__ == '__main__': loop.run_until_complete(test3())

创建task对象的3种方法,三种方法都可,看个人习惯

复制代码
  • 1
  • 2
  • 3
loop.create_task asyncio.create_task asyncio.ensure_future
posted @   Franciszw  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开