{"title":"异步支持","version":"3.0","locale":"zh-hans","docname":"topics/async","url":"/zh-hans/3.0/topics/async/","canonical":"https://djangodocs.dev/zh-hans/3.0/topics/async/","summary":"New in Django 3.0 Django 已对异步 (\"async\") Python 进行了支持，但还没有支持异步视图或中间件；它们可能在未来的版本中支持。 对异步生态系统的其他部分的支持有限；换句话说，Django 原生的使用 ASGI 和一些异步安全的支持。 异步安全 Link to this heading #…","html":"<h1>异步支持<a class=\"heading-anchor\" href=\"#asynchronous-support\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<aside class=\"version-note version-added\" data-version=\"3.0\">\n<p class=\"version-note-title\">New in Django 3.0</p></aside>\n<p>Django 已对异步 (&quot;async&quot;) Python 进行了支持，但还没有支持异步视图或中间件；它们可能在未来的版本中支持。</p>\n<p>对异步生态系统的其他部分的支持有限；换句话说，Django 原生的使用 <a class=\"reference internal\" href=\"/zh-hans/3.0/howto/deployment/asgi/\"><span class=\"doc\">ASGI</span></a> 和一些异步安全的支持。</p>\n<section id=\"async-safety\">\n<span id=\"id1\"></span><h2>异步安全<a class=\"heading-anchor\" href=\"#async-safety\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 的一些关键部分无法在异步环境里安全运行，因为它们的全局状态不支持协同工作。这些 Django 部分被归类为 &quot;不安全异步&quot;，并且受到保护，无法在异步环境中执行。ORM 是主要的例子，但其他部分也以这种方式受到保护。</p>\n<p>如果你试着从具有 <em>运行事件循环</em> 的线程中运行这些部分中的任何一个，你将得到 <a class=\"reference internal\" href=\"/zh-hans/3.0/ref/exceptions/#django.core.exceptions.SynchronousOnlyOperation\" title=\"django.core.exceptions.SynchronousOnlyOperation\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">SynchronousOnlyOperation</span></code></a> 错误。注意，你不必在异步函数内部即可得到这个错误。如果你直接从一个异步函数中调用了同步函数，而没有经过类似 <a class=\"reference internal\" href=\"#asgiref.sync.sync_to_async\" title=\"asgiref.sync.sync_to_async\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code></a> 或线程池之类的操作，那么它也可能会报这个错误，因为你的代码仍然在异步上下文中运行。</p>\n<p>如果遇到了这个错误，你应该修改代码以免在异步上下文中调用这个有问题的代码；相反，你可以编写代码在同步函数中与不安全异步交流，使用  <a class=\"reference internal\" href=\"#asgiref.sync.sync_to_async\" title=\"asgiref.sync.sync_to_async\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">asgiref.sync.sync_to_async()</span></code></a> 或在它自己线程内部运行任何其他首选方式来调用。</p>\n<p>如果你 <em>绝对</em> 迫切需要从异步上下文中运行此代码 - 比如，它是由外部环境强加给你，并且你确定它不会同时运行（例如在 <a class=\"reference external\" href=\"https://jupyter.org/\">Jupyter</a> notebook 里），那你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">DJANGO_ALLOW_ASYNC_UNSAFE</span></code> 环境变量来禁用告警。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>如果启用了这个选项，并且同时访问 Django 的异步不安全 (async-unsafe) 部分，你会遇到数据丢失或损坏，所以一定要非常小心，并且不要再生产环境里这样使用。</p>\n</aside>\n<p>如果你需要在 Python 中执行此操作，请使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">os.environ</span></code> ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">environ</span><span class=\"p\">[</span><span class=\"s2\">&quot;DJANGO_ALLOW_ASYNC_UNSAFE&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;true&quot;</span>\n</code></pre></div>\n</section>\n<section id=\"async-adapter-functions\">\n<h2>异步适配函数<a class=\"heading-anchor\" href=\"#async-adapter-functions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当从异步的上下文中调用同步的代码时，有必要适配调用风格，反之亦然。为此，有两个适配器功能，可从 <code class=\"docutils literal notranslate\"><span class=\"pre\">asgiref.sync</span></code> 包中获取：<a class=\"reference internal\" href=\"#asgiref.sync.async_to_sync\" title=\"asgiref.sync.async_to_sync\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_to_sync()</span></code></a> 和 <a class=\"reference internal\" href=\"#asgiref.sync.sync_to_async\" title=\"asgiref.sync.sync_to_async\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code></a> 。它们用于同步和异步之间调用风格的转换，同时保持兼容性。</p>\n<p>这些适配函数广泛应用于 Django。<a class=\"reference external\" href=\"https://pypi.org/project/asgiref/\">asgiref</a> 包本身就是 Django 项目的部分，并且它在当你用 <code class=\"docutils literal notranslate\"><span class=\"pre\">pip</span></code> 方式安装 Django 时，会作为依赖项目自动安装。</p>\n<section id=\"async-to-sync\">\n<h3><code class=\"docutils literal notranslate\"><span class=\"pre\">async_to_sync()</span></code><a class=\"heading-anchor\" href=\"#async-to-sync\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"asgiref.sync.async_to_sync\">\n<span class=\"sig-name descname\"><span class=\"pre\">async_to_sync</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">async_function</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">force_new_loop</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#asgiref.sync.async_to_sync\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>包装一个异步函数并且返回一个同步函数。可以用作直接包装器或装饰器：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">asgiref.sync</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">async_to_sync</span>\n\n<span class=\"n\">sync_function</span> <span class=\"o\">=</span> <span class=\"n\">async_to_sync</span><span class=\"p\">(</span><span class=\"n\">async_function</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@async_to_sync</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">async_function</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>如果存在异步函数，那么它会在当前线程的事件循环中运行。如果没有当前事件循环，则会为异步函数专门启动一个新的事件循环，并且会在它完成后再次关闭。无论哪种情况，异步函数会在调用代码的不同线程上执行。</p>\n<p>Threadlocals 和 contextvars 值在两个方向的边界上都保持不变。</p>\n<p><a class=\"reference internal\" href=\"#asgiref.sync.async_to_sync\" title=\"asgiref.sync.async_to_sync\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_to_sync()</span></code></a> 本质上是 Python 标准库中 <a class=\"reference external\" href=\"https://docs.python.org/3/library/asyncio-runner.html#asyncio.run\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">asyncio.run()</span></code></a> 函数更强大的版本。在确保 threadlocals 工作之外，当在它下面使用包装时，它也会启用 <a class=\"reference internal\" href=\"#asgiref.sync.sync_to_async\" title=\"asgiref.sync.sync_to_async\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code></a> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive</span></code> 模式。</p>\n</section>\n<section id=\"sync-to-async\">\n<h3><code class=\"docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code><a class=\"heading-anchor\" href=\"#sync-to-async\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"asgiref.sync.sync_to_async\">\n<span class=\"sig-name descname\"><span class=\"pre\">sync_to_async</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">sync_function</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">thread_sensitive</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#asgiref.sync.sync_to_async\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>包装一个同步函数并且返回一个异步函数。可以用作直接包装器或装饰器：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">asgiref.sync</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">sync_to_async</span>\n\n<span class=\"n\">async_function</span> <span class=\"o\">=</span> <span class=\"n\">sync_to_async</span><span class=\"p\">(</span><span class=\"n\">sync_function</span><span class=\"p\">)</span>\n<span class=\"n\">async_function</span> <span class=\"o\">=</span> <span class=\"n\">sync_to_async</span><span class=\"p\">(</span><span class=\"n\">sensitive_sync_function</span><span class=\"p\">,</span> <span class=\"n\">thread_sensitive</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@sync_to_async</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">sync_function</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>Threadlocals 和 contextvars 值在两个方向的边界上都保持不变。</p>\n<p>同步函数倾向于假设它们在主线程中运行时编写，因此 <a class=\"reference internal\" href=\"#asgiref.sync.sync_to_async\" title=\"asgiref.sync.sync_to_async\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code></a> 有两个线程模式：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive=False</span></code> (默认)：同步函数将在一个全新的线程中运行，该线程一旦完成，将会关闭。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive=True</span></code>: 同步函数将与所有其它  <code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive</span></code>  函数在相同线程里运行，如果主线程是同步的并且你正在使用 <a class=\"reference internal\" href=\"#asgiref.sync.async_to_sync\" title=\"asgiref.sync.async_to_sync\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_to_sync()</span></code></a> 装饰器，则该同步函数将成为主线程。</p></li>\n</ul>\n<p>Thread-sensitive(线程敏感)模式非常特殊，在同一个线程中运行所有函数需要做很多工作。但是请注意，它依赖于堆栈中它上面的 <a class=\"reference internal\" href=\"#asgiref.sync.async_to_sync\" title=\"asgiref.sync.async_to_sync\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_to_sync()</span></code></a> 的使用，以便在主线程上正确运行。如果你使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">asyncio.run()</span></code> (或其他选项代替)，它将退回到单独共享线程（但不是主线程）中运行 thread-sensitive 函数。</p>\n<p>在 Django 中需要这么做的原因是许多库，特别是数据库适配器，要求它们在创建时所在的同一个线程里对其进行访问，并且许多现有的 Django 代码假设它都在同一进程中运行（比如中间件将内容添加到请求中以供视图稍后使用）。</p>\n<p>我们没有引入代码潜在的兼容性问题，而是选择了添加这种模式，以便所有现有的 Django 同步代码都在同一个线程中运行，从而完全兼容异步模式。注意，同步代码始终要与调用它的异步代码保持在不同线程中，所以你应该避免在任何你编写的新代码中传递原始数据库句柄(handles)或者其他 thread-sensitive 引用。</p>\n</section>\n</section>","rootId":"asynchronous-support","toc":[{"title":"异步安全","anchor":"async-safety","children":[]},{"title":"异步适配函数","anchor":"async-adapter-functions","children":[{"title":"async_to_sync()","anchor":"async-to-sync","children":[]},{"title":"sync_to_async()","anchor":"sync-to-async","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/3.0/topics/"}],"prev":{"docname":"topics/external-packages","title":"扩展包","url":"/zh-hans/3.0/topics/external-packages/"},"next":{"docname":"howto/index","title":"操作指南","url":"/zh-hans/3.0/howto/"},"formats":{"html":"/zh-hans/3.0/topics/async/","markdown":"/zh-hans/3.0/topics/async.md","json":"/zh-hans/3.0/topics/async.json"},"source":"https://github.com/django/django/blob/stable/3.0.x/docs/topics/async.txt","official":"https://docs.djangoproject.com/zh-hans/3.0/topics/async/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}