如果我有下面的代码,变量service
如何影响端点的异步性质?变量会被共享吗?还是在使用时会将其锁定,从而阻止其他端点访问它,直到当前端点完成?
我问上面的假设服务实例是无状态的,即如果我在每个端点中创建一个服务实例,这将是等效的。我不愿意这样做,因为我不知道哪个更耗时,实例化和销毁服务对象或共享一个?
from typing import List, Union
from fastapi import APIRouter, Body, Depends
# Service definition
router = APIRouter()
service = Service()
@router.post("/a", response_model=Union[A, None])
async def x():
service.start()
pass
@router.post("/b", response_model=Union[B, None])
async def y():
service.stop()
pass
变量服务将如何影响端点的异步性质?
首先,如果您的service.stop()
不是协程,则异步不会执行任何上下文切换。
这意味着它将阻止。
这也意味着你的函数必须是awaitable
的,它必须是屈服的。
还是在使用时会被锁定
如果可能存在争用条件,它不会自动锁定。您需要锁定它(请参阅异步。锁())。
但是,如果您的代码不执行任何上下文切换。您不必担心这一点,因为两个协程不能同时执行,并发性不是并行性。
在事件循环(执行协程的地方)中,协程生成要恢复的事件。事件循环能够等待这些事件发生。但是在等待的同时,它也可以等待其他事件,或者它可以处理其他事件。这仅在您有一个协程时才有效,事件通信由事件循环的生成控制完成。
但是当两个事件共享同一个List
时你应该怎么做,你需要锁定它。
为了更清楚地说明这一点,假设您的代码是一家餐厅,协程是女服务员,您向女服务员下达命令,然后她前往厨师(事件循环)
你需要等待,你也不能分享酋长,而酋长可以同时做两个汉堡包(处理两个不同的事件)
当他没有足够大的网格来同时制作两个汉堡包(共享对象)时会发生什么?
当您的订单正在等待时,您需要锁定网格两个使其他客户订购,但您不能共享网格,因为您有一个网格,您需要说"嘿,我需要锁定这里">
但是你仍然可以吃沙拉(其他协程不会被阻止)。
所以在这种情况下,如果我在它们中的每一个中执行 Service().start() 会不会更慢?
TL;博士
这个问题完全取决于您的start()
函数的作用以及它的作用。
好的,但我需要更好地理解异步。
然后假设您有以下代码
async def x():
a = await service.start()
return a
- 这将为生成变量分配堆栈空间
service().start()
- 事件循环将执行此操作并跳转到下一条语句
- 一旦
start()
get被执行,它将推动调用堆栈的值 - 这将存储堆栈和指令指针。
- 然后它将生成的变量从
service().start()
存储到a
,然后它将恢复堆栈和指令指针。
- 一旦
- 当涉及到
return a
时,这会将 a 的值推送到调用堆栈。 - 毕竟它将清除堆栈和指令指针。
请注意,我们能够完成所有这些操作,因为service().start()
是一个协程,它是yielding
而不是返回。
乍一看,您可能不清楚,但正如我提到的async
和await
只是用于声明和管理协程的花哨语法。
import asyncio
@asyncio.coroutine
def decorated(x):
yield from x
async def native(x):
await x
但是这两个功能是相同的,做完全相同的事情。您可以考虑yield from
一个或多个函数链接在一起。
但是,要深入了解异步 I/O,我们需要了解它的作用以及它如何在下面执行。
在大多数操作系统中,基本 API 可用于select()
或poll()
系统调用。
这些接口使 API 的用户能够检查是否有任何应处理的传入 I/O。
例如,您的 HTTP 服务器想要检查是否有任何网络数据包到达以便为它们提供服务。借助此系统调用,您可以检查这一点。
当我们检查select()
的手册页时,我们将看到此描述。
select() 和 pselect() 允许程序监视多个文件解 脚本,等待一个或多个文件描述符变为 "准备好"用于某些类别的 I/O 操作(例如,可能的输入)。 一个文件如果可以执行相应的描述符,则认为描述符已准备就绪‐ 冲击 I/O 操作
这为您提供了一个非常基本的概念,并解释了异步 I/O 的本质。
它允许您检查是否可以读取和写入描述符。
它通过不阻塞其他内容使您的代码更具可扩展性。作为奖励,您的代码会变得更快,但这不是异步 I/O 的实际目的。
所以要整理。
事件循环只是不断产生,而某些东西已经准备好了。通过这样做,它不会阻塞。