ASGI规范、辅助代码和适配器
项目描述
ASGI是Python异步Web应用和服务器之间通信的标准,定位为WSGI的异步继任者。您可以在此了解更多信息:https://asgi.readthedocs.io/en/latest/
此包包括ASGI基础库,例如
同步到异步和异步到同步函数包装,asgiref.sync
服务器基类,asgiref.server
ASGI到WSGI的适配器,位于
asgiref.wsgi
函数包装器
这些允许您包装或装饰异步或同步函数,以便可以从另一种样式调用它们(因此您可以从同步线程调用异步函数,反之亦然)。
特别是
AsyncToSync允许同步子线程在主线程的事件循环上调用异步函数时停止并等待,然后在异步函数完成时将控制权返回给线程。
SyncToAsync允许异步代码调用同步函数,该函数在线程池中运行,并在同步函数完成时将控制权返回给异步协程。
目的是使从异步代码调用同步API和从同步代码调用异步API变得更容易,以便更容易从一种样式过渡到另一种样式。在Channels的情况下,我们使用SyncToAsync包装(同步的)Django视图系统,以便它在(异步的)ASGI服务器中运行。
请注意,事物运行在哪些线程中是非常具体的,旨在与旧同步代码保持最大兼容性。有关完整说明,请参阅下文中的“同步代码 & 线程”。默认情况下,sync_to_async
将出于安全原因在程序中的同一线程中运行所有同步代码;您可以通过使用@sync_to_async(thread_sensitive=False)
来禁用此功能以获得更高的性能,但请确保在执行时您的代码不依赖于绑定到线程的任何内容(如数据库连接)。
Threadlocal替换
这是一个可以用于线程和asyncio任务的Threadlocal替换。更好的是,当您使用sync_to_async
在线程池中运行事物时,它将代理从任务局部上下文到线程局部上下文的值,反之亦然。
如果您想要真正的线程和任务安全性,您可以在Local对象上设置thread_critical
以确保这一点。
服务器基类
包括一个StatelessServer
类,它提供了编写无状态服务器(即不处理直接传入的套接字,而是消费外部流或套接字以确定正在发生的事情)的所有困难工作。
这样的服务器的一个例子是聊天机器人服务器,该服务器连接到中央聊天服务器并为与它聊天的每个用户提供一个“连接作用域”。只有一个实际连接,但服务器必须将事物分开成几个作用域,以便更容易编写代码。
您可以在frequensgi中看到如何使用此示例。
WSGI-to-ASGI适配器
允许您包装一个WSGI应用程序,使其看起来像一个有效的ASGI应用程序。
只需像这样将其包装在您的WSGI应用程序周围
asgi_application = WsgiToAsgi(wsgi_application)
WSGI应用程序将在同步线程池中运行,包装的ASGI应用程序将是一个接受http类消息的应用程序。
请注意,WSGI的所有扩展功能可能不支持(例如,用于传入POST主体的文件句柄)。
依赖关系
asgiref
需要Python 3.8或更高版本。
贡献
请参阅主要Channels贡献文档。
测试
要运行测试,请确保您已使用与包一起安装的tests
额外功能。
cd asgiref/ pip install -e .[tests] pytest
构建文档
文档使用Sphinx。
cd asgiref/docs/ pip install sphinx
要构建文档,您可以使用默认工具
sphinx-build -b html . _build/html # or `make html`, if you've got make set up cd _build/html python -m http.server
…或者您可以使用sphinx-autobuild
来运行服务器并自动重建/重新加载您的文档更改
pip install sphinx-autobuild sphinx-autobuild . _build/html
发布
要发布,首先在CHANGELOG.txt中添加详细信息,并更新asgiref/__init__.py
中的版本号。
然后,构建并推送包
python -m build twine upload dist/* rm -r build/ dist/
实现细节
同步代码 & 线程
《asgiref.sync》模块提供了两个包装器,允许您在异步和同步代码之间随意切换,同时为您处理粗糙的边缘。
不幸的是,粗糙的边缘很多,代码需要特别努力才能尽可能地在同一个线程中保持事物的同步。值得注意的是,我们正在处理以下限制
通过《SyncToAsync》调用并标记为《thread_sensitive》的所有同步代码应在同一线程中运行(如果程序的外层是同步的,则为主线程)
如果线程已经有一个正在运行的异步循环,那么如果它在调用栈中阻塞在您之上的同步代码上,则《AsyncToSync》无法在该循环上运行事物。
您可能得到的第一个妥协可能是,《thread_sensitive》代码应仅在同一个线程中运行,而不是在子线程中启动,以满足第一个限制,但这立即导致第二个限制。
唯一的真正解决方案是在ThreadPoolExecutor的一个变体中执行任何《thread_sensitive》代码,使其在最外层的同步线程上运行 - 要么是主线程,要么是单个生成的子线程。
这意味着您现在有两个基本状态
如果程序的外层是同步的,那么通过《AsyncToSync》运行的所有异步代码将在任意子线程中的每个调用事件循环中运行,而所有《thread_sensitive》代码将在主线程中运行。
如果程序的外层是异步的,那么所有异步代码都在主线程的事件循环上运行,而所有《thread_sensitive》同步代码都在单个共享子线程中运行。
关键的是,这意味着在两种情况下,都有一个线程是共享资源,所有《thread_sensitive》代码都必须在该线程上运行,而且有可能这个线程目前正在阻塞在其自己的《AsyncToSync》调用上。因此,《AsyncToSync》需要在其阻塞期间充当线程代码的执行器。
《CurrentThreadExecutor》类提供了这个功能;您不仅可以等待Future,还可以调用它的《run_until_future》方法,它将运行提交的代码直到该Future完成。这意味着可以在调用内部运行代码在您的线程上。
维护和安全
要报告安全问题,请联系 security@djangoproject.com。有关GPG签名和更多信息,请参阅 https://docs.django.ac.cn/en/dev/internals/security/。
要报告错误或请求新功能,请打开一个新的GitHub问题。
此存储库是Channels项目的一部分。对于牧羊人和维护团队,请参阅 主Channels说明文件。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分布
构建分布
asgiref-3.8.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590 |
|
MD5 | fb2927e26ea34c97e0a4c89612e80562 |
|
BLAKE2b-256 | 2938b3395cc9ad1b56d2ddac9970bc8f4141312dbaec28bc7c218b0dfafd0f42 |
asgiref-3.8.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 |
|
MD5 | 87ef2494bf2bb208cd3652e577c74bc9 |
|
BLAKE2b-256 | 39e3893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e |