文章目录

lscpu,thread(s) per core, Core(s) per socket,Socket(s)

CPU(s):                  16
Thread(s) per core:  2
Core(s) per socket:  8
Socket(s):           1
参数 含义 例子
Socket(s) CPU 插槽数(物理 CPU 芯片有几块) 1(主板上只有一块 CPU 芯片)
Core(s) per socket 每块芯片上的物理核心数 8(这块 CPU 内有 8 个真正的硬件核心)
Thread(s) per core 每个物理核心的超线程数 2(开启了超线程,1 个物理核模拟 2 个逻辑核)
CPU(s) 总逻辑 CPU 数 16(操作系统看到的总 CPU 线程数)

总逻辑 CPU 数 = Socket(s) × Core(s) per socket × Thread(s) per core \text{总逻辑 CPU 数} = \text{Socket(s)} \times \text{Core(s) per socket} \times \text{Thread(s) per core} 总逻辑 CPU =Socket(s)×Core(s) per socket×Thread(s) per core

在这里插入图片描述

物理核心是真正存在的 CPU 计算单元
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

物理核心:
是真正的计算并行
超线程:
属于部分并行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

什么时候看物理核心?逻辑核心?

在这里插入图片描述

物理核心决定真正的并行计算能力;逻辑核心(超线程)是在一个物理核心空闲时,让另一个线程利用剩余资源,提高吞吐量。它不是两个核心轮流执行,而是两个线程共享一个核心的执行资源。

在这里插入图片描述

进程和线程是什么?CPU实际执行的是:线程

进程是一个正在运行的程序实例。
线程是进程里面真正执行代码的单位
CPU实际执行的是:
线程
不是进程。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

什么是协程?协程是一种运行在线程里的、可以暂停和恢复的任务。事件循环负责在多个协程之间切换

线程是操作系统调度的
线程切换由操作系统决定
协程不是操作系统资源
协程是在一个线程里面运行的
协程之间的切换由程序自己决定
IO密集型:协程优势巨大
CPU密集型:协程没优势
协程
解决:
大量等待任务不要浪费线程
依靠:
一个线程 + 主动让出

在这里插入图片描述
在这里插入图片描述

为什么叫“可以暂停和恢复”?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

怎么判断是不是协程?看有没有 async def

看到:

async def

基本可以判断:

这是一个协程函数

async def 定义出来的函数叫“协程函数(coroutine function)”。调用协程函数以后不会立马执行,而是返回一个“协程对象(coroutine object)”

在这里插入图片描述

什么是协程函数?协程函数就是:用 async def 定义的函数

在这里插入图片描述

什么是协程对象?一个“还没有执行的任务”。

调用协程函数以后不会立马执行,而是返回一个“协程对象(coroutine object)”

在这里插入图片描述
在这里插入图片描述

协程对象不能自己执行,必须交给某种“运行器”执行;在 Python 的 asyncio 体系里,通常就是由事件循环(event loop)来执行。事件循环负责调度它、暂停它、恢复它

在这里插入图片描述

不是所有带 async 的东西都是协程函数

async with
async with lock:

这是异步上下文管理。
不是定义协程。
async for
async for item in stream:

这是异步迭代。
不是定义协程。

在这里插入图片描述

async with 异步上下文管理器

async with 是 Python 异步上下文管理器(asynchronous context manager),它和普通的 with 很像。
为什么需要 async with?
因为有些资源的获取和释放也是异步的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import asyncio


class AsyncResource:

    async def __aenter__(self):
        print("建立连接")
        await asyncio.sleep(1)
        return self


    async def __aexit__(self, exc_type, exc, tb):
        print("关闭连接")
        await asyncio.sleep(1)


    async def work(self):
        print("执行任务")
async def main():

   async with AsyncResource() as r:
       await r.work()


asyncio.run(main())

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

async with 异步函数 async def 里面使用

在这里插入图片描述

async for 每次获取下一个元素时,可能需要等待,所以允许异步等待

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import asyncio


class AsyncCounter:

    def __init__(self):
        self.i = 0


    def __aiter__(self):
        return self


    async def __anext__(self):

        if self.i >= 3:
            raise StopAsyncIteration

        await asyncio.sleep(1)

        self.i += 1

        return self.i
async def main():

    async for x in AsyncCounter():
        print(x)


asyncio.run(main())

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

async for 必须出现在异步上下文中,也就是协程函数(async def)里面。async for 本质就是帮你自动写了:await 下一条数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

协程,线程,进程

在这里插入图片描述

在这里插入图片描述

多线程 多进程 concurrent.futures.Future

from concurrent.futures import ThreadPoolExecutor
ThreadPoolExecutor,线程池执行器
from concurrent.futures import ProcessPoolExecutor
pool = ProcessPoolExecutor(max_workers=4)

在这里插入图片描述

ThreadPoolExecutor(max_workers=x),最多同时运行max_workers个线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

submit,返回concurrent.futures.Future

future = pool.submit(
函数,
参数
)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Future怎么拿结果? concurrent.futures.Future 获取的是“提交给线程池/进程池执行的那个函数的返回结果”

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

按提交顺序获取结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

谁完成先拿谁” concurrent.futures.as_completed()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

多个任务怎么执行?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

为什么叫 Pool(池)? 因为线程可以重复利用。

在这里插入图片描述
在这里插入图片描述

ProcessPoolExecutor(max_workers=4),最多同时执行max_workers个进程

在这里插入图片描述
在这里插入图片描述

pool.submit(square,10),返回Feature

在这里插入图片描述
在这里插入图片描述

Feature怎么拿结果 concurrent.futures.Future 获取的是“提交给线程池/进程池执行的那个函数的返回结果”

在这里插入图片描述
在这里插入图片描述

按提交顺序拿结果

在这里插入图片描述

谁先完成先拿谁

在这里插入图片描述

多任务并行

在这里插入图片描述
在这里插入图片描述

ProcessPoolExecutor 叫“进程池”,因为它提前管理一批可重复使用的进程

线程池和进程池中的“池”,就是指创建一批线程/进程放在那里,任务来了直接复用,不需要每次重新创建和销毁

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

concurrent.futures.Future 是“线程安全”的,因为多个线程可以访问同一个 Future 对象;ProcessPoolExecutor 虽然也返回它,但这个 Future 只存在于主进程,子进程通过 IPC 返回结果,由主进程里的 Future 更新,所以不存在 Future 跨进程共享的问题

线程内存共享,进程内存隔离

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

IPC 是 Inter-Process Communication(进程间通信) 的缩写。因为进程之间内存隔离,一个进程不能直接访问另一个进程的变量,所以必须通过特殊机制通信

IPC 就是让两个独立进程之间交换数据、发送消息、同步状态的方法。
因为进程之间内存隔离,一个进程不能直接访问另一个进程的变量,所以必须通过特殊机制通信。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Task 可以理解成:Event Loop 管理的“正在执行的协程任务”。协程对象不一定必须手动变成 Task,Event Loop 才能执行。很多情况下,Event Loop 会自动把协程对象包装成 Task

协程对象不一定必须手动变成 Task,Event Loop 才能执行。
很多情况下,Event Loop 会自动把协程对象包装成 Task
1、直接交给 run_until_complete,run_until_complete()-》自动包装成 Task-》 Event Loop执行
2、手动创建 Task,task = asyncio.create_task(协程对象)
3、协程对象直接 await,
async def main():
await hello()
hello()

协程对象

await

Event Loop执行
也没有显式 Task。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

谁执行协程?谁负责切换协程?事件循环 Event Loop

协程不是操作系统执行的,而是由线程里的事件循环(Event Loop)负责调度和切换。
真正执行协程代码的,还是某个线程里的 CPU。
负责“什么时候运行哪个协程”的,是 Event Loop。
Event Loop 可以理解为:
一个不断循环运行的“任务调度器”。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Future 是一个“未来结果的占位盒子”。现在没有结果,但是以后会有结果。协程对象描述“要做什么”;Task负责“什么时候做”;Future负责“做完得到什么”。

Future不是任务,它只是“结果等待凭证”。线程池/进程池用 Future 等线程或进程的结果;asyncio 用 Future 等协程的结果。

Future:
不是一个函数。
它表示:
某个异步操作未来会产生结果。
Task 是 Future 的一种特殊形式
Task 是 Future 的子类
Future 自己不知道“怎么做完”,也不知道“做什么”。
Future 只是一个空盒子,别人负责把结果放进去。
它不是预测未来,而是保存未来结果的容器。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建 Future 只有 loop.create_future() 吗?asyncio 的 Future 必须和某个 Event Loop 关联

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

future设置结果只有 set_result() 吗?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

asyncio.Future属于 asyncio。concurrent.futures.Future它用于线程池、进程池。

在这里插入图片描述

asyncio 是什么?Python 官方提供的异步编程框架

先看名字:
asyncio
|
|-- async(异步)
|
|-- io(输入输出)
它是 Python 官方提供的异步编程框架。
它主要提供:
协程(coroutine)
事件循环(Event Loop)
Task
Future
异步 IO
也就是说:
asyncio 是管理协程运行的一整套工具。

在这里插入图片描述

什么是事件循环?事件循环(Event Loop)就是一个不断循环运行的调度器,负责检查有哪些任务可以执行,然后安排它们运行。它是 asyncio 异步编程的核心。事件循环绑定并运行在线程中,是运行在线程中的一个调度器,而线程属于某个进程

在这里插入图片描述

创建 Event Loop 有几种方式?

1、手动创建:loop = asyncio.new_event_loop(),只是创建,还没运行

在这里插入图片描述

asyncio.new_event_loop() 创建 Event Loop 不等于运行

在这里插入图片描述
在这里插入图片描述

run_forever() 永远运行:启动事件循环,一直循环调度任务,直到有人调用 stop

run_forever没有参数
但是你可能会疑惑:
那它启动 Event Loop 后,运行什么?
答案:
它运行的是已经提交到这个 Event Loop 里的任务(Task / callback / coroutine)。
不是通过参数传进去。

在这里插入图片描述
在这里插入图片描述

run_until_complete() 运行一个协程,直到它完成,然后退出

loop.run_until_complete(x)
需要一个:
可以等待完成的东西,可以是
1、调用 async def 定义的函数后产生的协程对象
2、Task
3、Feature
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法2:asyncio.run()最常用

asyncio.run(
main(), # 必填:一个协程对象
debug=True # 可选:调试模式
)
asyncio.run() 的参数是 调用 async def函数后返回的协程对象(coroutine object)。

在这里插入图片描述
在这里插入图片描述

方法3:获取已有 Event Loop asyncio.get_running_loop()

在这里插入图片描述

为什么loop = asyncio.get_running_loop()必须在协程里调用?

asyncio.get_running_loop() 必须在协程里调用,是因为它获取的是当前正在运行的 Event Loop,而只有进入协程执行阶段时,Python 才知道“当前线程正在运行哪个 Event Loop”。

在这里插入图片描述
在这里插入图片描述

loop.stop():让事件循环停止运行。loop.close():关闭事件循环,释放资源,让它不能再使用。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

asyncio.run()为什么不用手动close?

在这里插入图片描述
在这里插入图片描述

loop.stop() 不会等待任务完成,也不会自动取消任务。它只是告诉 Event Loop:“不要再继续循环调度了”

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

loop.call_soon(loop.stop)

call_soon() 的意思:
不马上执行这个函数,而是把这个函数放到 Event Loop 的任务队列里,等 Event Loop 下一次循环时执行。
call_soon接收的是函数对象(即函数名)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

await只能写在哪里?后面可以跟什么?跟不同内容的作用分别是什么 await 到底是什么意思?

await 会暂停当前协程,把后面那个异步对象交给 Event Loop 去推进执行;当前协程等待它完成后,再继续往下执行

await 是协程主动让出执行权的方式。它等待一个异步对象(协程、Task、Future)的结果,但等待期间不会阻塞 Event Loop,而是让 Event Loop 去执行其他任务

遇到 await 时,只是当前协程主动暂停,并告诉 Event Loop:“我要等这个东西,你之后帮我恢复”

await 会暂停当前协程,把后面那个异步对象交给 Event Loop 去推进执行;当前协程等待它完成后,再继续往下执行

await 后面的东西,不一定会被 Event Loop 立即执行。
await 只是建立一个“等待关系”:当前协程暂停,等待这个对象完成。至于这个对象什么时候执行、是否已经在执行,要看它是什么类型(协程对象,task,future)

await 不负责启动后面的对象,它只是让当前协程等待该对象完成;对象是否已经运行、何时运行,由 Event Loop 中对应的调度状态决定

“await等待的那个异步对象完成”,后,Event Loop 会知道,然后自动恢复当前协程,不需要你手动通知。

await Future/Task:等待一个已经存在的异步任务完成;await coroutine:启动并驱动这个协程执行,期间如果遇到等待点则挂起当前协程

在这里插入图片描述

“await等待的那个异步对象(协程对象,Task,featur)完成”,后,Event Loop 会知道,然后自动恢复当前协程,不需要你手动通知。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

await 后面的东西,不一定会被 Event Loop 立即执行。await 只是建立一个“等待关系”:当前协程暂停,等待这个对象完成。至于这个对象什么时候执行、是否已经在执行,要看它是什么类型(协程对象,task,future).await 后面必须是:Coroutine对象,Task,Future

await 后面必须是:
Coroutine对象
Task
Future

await 协程对象

await后面跟协程对象时,会让当前协程暂停,并建立“等待该协程对象完成”的关系。Event Loop随后负责驱动这个协程对象执行(具体什么时候执行由调度决定),当该协程对象完成后,Event Loop自动恢复await所在的协程

协程对象:创建时没有进入 Event Loop
await 协程对象时
Event Loop 才开始接触这个 coroutine,并负责推进它
在这里插入图片描述

await Task

await Task 不负责启动任务,它只是等待一个已经存在的 Task 完成。当前协程等待这个 Task 完成。
创建 Task:
task = asyncio.create_task(worker())
Task 在创建时,就已经被注册到 Event Loop 的调度体系中,等待执行
Task = 已经交给 Event Loop 管理的执行任务

在这里插入图片描述

await Future

Future 本身没有要执行的东西。
Future ≠ 要执行的东西
它只是:
一个未来结果的容器
Event Loop知道:
当前协程
正在等待 Future
但是注意:
Event Loop不会说:
Future,你开始执行
因为 Future没有执行逻辑。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

await 只能写在 async def 定义的协程函数里面

在这里插入图片描述
在这里插入图片描述

asyncio.run() 创建 Event Loop → 执行一个协程 → 等协程结束 → 关闭 Event Loop。返回最外层协程的 return 值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

asyncio.create_task()。把一个 Coroutine 包装成 Task,并立即提交给当前 Event Loop 调度。返回 Task对象。可await,不await

asyncio.create_task() 创建 Task 后,Task 会进入 Event Loop 调度,是否 await 取决于你是否需要等待它完成、获取结果
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

asyncio.gather() 同时运行多个协程,并等待它们全部完成,然后返回所有结果。返回future,需要await. await后返回一个列表,里面是每个任务的结果。

gather() 会把多个可等待对象(Coroutine/Task/Future)组合起来,让它们被调度执行,并返回一个代表“全部完成状态”的 Future,方便一次性等待所有结果。
asyncio.gather(coro1,coro2) 会把多个 Coroutine 交给 asyncio 管理(通常转换为 Task),让 Event Loop 可以调度它们,并返回一个 Future,用于等待所有任务完成并收集结果
需要 await 的一个核心原因就是:让当前协程等待这个 Future 完成,并拿到结果。
如果不加 await,当前协程会继续往下执行
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

asyncio.sleep() 异步睡眠。返回一个协程对象,不会立即执行,需要await

sleep coroutine 也需要被 Event Loop 推进后才会开始计时。因为 await sleep() 通常发生在当前正在运行的 Task 中,所以 Event Loop 很快执行 sleep 的内部逻辑并注册定时器,因此通常认为计时从 await 开始。
“创建协程 ≠ 执行协程;进入 Event Loop 调度 ≠ 已经运行
syncio.sleep
本身是一个:
用 async def 定义的协程函数(coroutine function)
调用它:asyncio.sleep(3)返回
一个协程对象(coroutine object)

在这里插入图片描述
在这里插入图片描述

什么叫“可等待对象(Awaitable)”? 可等待对象,就是可以被 await 等待的东西

在这里插入图片描述

线程 A 不能直接操作线程 B 的事件循环

如果“线程 A”想让“线程 B”里的事件循环帮它运行一个异步函数 init_config_async(),你不能直接在线程 A 里 await,也不能直接调用 self.loop.create_task()(因为线程不安全)

不能直接在线程 A 里 await?await 只能写在 async def 定义的协程函数里面。await 的本质是:当前协程把控制权交给当前线程的事件循环,线程A没有事件循环

事件循环属于线程,事件循环运行在哪个线程,就属于哪个线程

在这里插入图片描述
在这里插入图片描述

为什么不能self.loop.create_task(init_config_async())?asyncio 规定:Event loop 对象不是线程安全的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

asyncio.run_coroutine_threadsafe() 是用于从一个线程向另一个线程中的事件循环提交协程任务的函数

asyncio 规定:Event loop 对象不是线程安全的。
asyncio.run_coroutine_threadsafe() 是用于从一个线程向另一个线程中的事件循环提交协程任务的函数
concurrent.Future 存放的是这个协程在目标事件循环中执行完成后的:
返回值
异常
取消状态

asyncio.run_coroutine_threadsafe(coro, loop)
它主要用于:
当前线程和事件循环所在的线程不是同一个线程时,安全地把协程提交到那个事件循环

在这里插入图片描述

例子

把一个协程 self.init_config_async(config) 提交到指定事件循环 self.loop 中执行,并立即返回一个可在线程间等待结果的 Future

# test_async.py
import asyncio
import threading
import time


class Manager:

    def __init__(self):
        # 1. 创建一个新的事件循环
        self.loop = asyncio.new_event_loop()

        # 2. 创建线程运行事件循环
        self.thread = threading.Thread(
            target=self.run_loop,
            daemon=True
        )

        self.thread.start()


    def run_loop(self):
        """
        子线程执行这个函数
        """

        # 把这个loop设置成当前线程的事件循环
        asyncio.set_event_loop(self.loop)

        print("事件循环启动")

        # 一直运行,等待任务
        self.loop.run_forever()


    async def init_config_async(self, config):
        """
        一个异步任务
        """

        print("开始执行异步任务")

        # 模拟网络请求
        await asyncio.sleep(3)

        print("异步任务完成")

        return {
            "config": config,
            "status": "ok"
        }


    def init_config(self, config):

        print("主线程提交任务")

        # 把协程提交给另一个线程的事件循环
        future = asyncio.run_coroutine_threadsafe(
            self.init_config_async(config),
            self.loop
        )


        print("任务已经提交,主线程继续")


        # 等待异步任务结果
        result = future.result()

        print("拿到结果:")
        print(result)



manager = Manager()


manager.init_config(
    {
        "name": "test"
    }
)

print("程序结束")

loop.call_soon_threadsafe(loop.stop) 的作用是:从其他线程安全地通知事件循环:请尽快执行 loop.stop(),停止事件循环

call_soon_threadsafe() 参数是普通函数
返回值是asyncio.Handle,拿不到会返回值,因为就不在意返回值。
需要结果使用run_coroutine_threadsafe
loop.stop()
作用:
设置一个标志,让事件循环在当前这一轮任务处理完成后退出

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐