并发编程与异步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协程整体是如何工作的

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可以用另一个函数把携程函数整合起来,并发的逻辑在整合函数中实现,但是如果方法不对可能无法实现并发

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种方法,三种方法都可,看个人习惯

loop.create_task
asyncio.create_task
asyncio.ensure_future
posted @ 2022-07-14 09:29  Franciszw  阅读(53)  评论(0编辑  收藏  举报