{"title":"异步支持","version":"6.1","locale":"zh-hans","docname":"topics/async","url":"/zh-hans/6.1/topics/async/","canonical":"https://djangodocs.dev/zh-hans/6.1/topics/async/","summary":"Django has support for writing asynchronous (\"async\") views, along with an entirely async-enabled request stack if you are running under ASGI . Async views will…","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<p>Django has support for writing asynchronous (&quot;async&quot;) views, along with an\nentirely async-enabled request stack if you are running under <a class=\"reference internal\" href=\"/zh-hans/6.1/howto/deployment/asgi/\"><span class=\"doc\">ASGI</span></a>. Async views will still work under WSGI, but\nwith a small per-request adaptation cost (see <a class=\"reference internal\" href=\"#async-performance\"><span class=\"std std-ref\">性能</span></a>), and\nwithout the ability to have efficient long-running requests.</p>\n<p>Many parts of Django provide asynchronous APIs, including <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/db/queries/#async-queries\"><span class=\"std std-ref\">the ORM</span></a>, the cache framework, authentication, sessions, and signals.\nFor other code, the <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> adapter is a low-cost bridge (see\n<a class=\"reference internal\" href=\"#async-performance\"><span class=\"std std-ref\">性能</span></a>). A wide range of async-native Python libraries can\nalso be integrated.</p>\n<section id=\"async-views\">\n<h2>异步视图<a class=\"heading-anchor\" href=\"#async-views\"><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\">async</span> <span class=\"pre\">def</span></code> 来实现这一点。对于基于函数的视图，这意味着要使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">def</span></code> 来声明整个视图。对于基于类的视图，这意味着要将 HTTP 方法处理程序，如 <code class=\"docutils literal notranslate\"><span class=\"pre\">get()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">post()</span></code> 声明为 <code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">def</span></code> （而不是 <code class=\"docutils literal notranslate\"><span class=\"pre\">__init__()</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">as_view()</span></code>）。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Django uses <code class=\"docutils literal notranslate\"><span class=\"pre\">inspect.iscoroutinefunction</span></code> to test if your view is\nasynchronous or not. If you implement your own method of returning a\ncoroutine, ensure you use <code class=\"docutils literal notranslate\"><span class=\"pre\">inspect.markcoroutinefunction</span></code> so this\nfunction returns <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>.</p>\n</aside>\n<p>在一个 WSGI 服务器下，异步视图将在它们自己的一次性事件循环中运行。这意味着你可以使用异步功能，比如并发的异步 HTTP 请求，而不会出现任何问题，但你不会得到异步堆栈的好处。</p>\n<p>主要的好处是能够在不使用 Python 线程的情况下处理数百个连接。这使你能够使用慢速流式传输、长轮询和其他令人兴奋的响应类型。</p>\n<p>如果你想使用这些特性，需要使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/howto/deployment/asgi/\"><span class=\"doc\">ASGI</span></a> 来部署 Django。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>A fully asynchronous request stack requires async middleware end-to-end.\nWhere a piece of synchronous middleware sits between an ASGI server and an\nasync view, Django adapts it by running it in its own thread; see\n<a class=\"reference internal\" href=\"#async-performance\"><span class=\"std std-ref\">性能</span></a> for the cost trade-off.</p>\n<p>Django's bundled middleware supports both <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/middleware/#async-middleware\"><span class=\"std std-ref\">sync and async</span></a>. Third-party middleware may not. To see which\nmiddleware Django adapts, turn on debug logging for the <code class=\"docutils literal notranslate\"><span class=\"pre\">django.request</span></code>\nlogger and look for log messages about <em>&quot;Asynchronous handler adapted for\nmiddleware ...&quot;</em>.</p>\n</aside>\n<p>在 ASGI 和 WSGI 模式里，你可以始终安全地使用异步支持来并发运行代码而不是串行。这在处理外部 API 或数据存储时特别方便。</p>\n<p>如果你想调用仍然是同步的 Django 部分，你需要将其包装在 <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<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\">results</span> <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"n\">sync_to_async</span><span class=\"p\">(</span><span class=\"n\">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><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"mi\">123</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你在异步视图中意外地尝试从 Django 中调用仅支持同步的部分，你将触发 Django 的 <a class=\"reference internal\" href=\"#async-safety\"><span class=\"std std-ref\">异步安全保护</span></a>，以保护你的数据免受损坏。</p>\n<section id=\"decorators\">\n<h3>装饰器<a class=\"heading-anchor\" href=\"#decorators\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>以下装饰器可以用于同步和异步视图函数：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.cache.cache_control\" title=\"django.views.decorators.cache.cache_control\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">cache_control()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.cache.never_cache\" title=\"django.views.decorators.cache.never_cache\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">never_cache()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.common.no_append_slash\" title=\"django.views.decorators.common.no_append_slash\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">no_append_slash()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csp/#django.views.decorators.csp.csp_override\" title=\"django.views.decorators.csp.csp_override\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csp_override()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csp/#django.views.decorators.csp.csp_report_only_override\" title=\"django.views.decorators.csp.csp_report_only_override\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csp_report_only_override()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csrf/#django.views.decorators.csrf.csrf_exempt\" title=\"django.views.decorators.csrf.csrf_exempt\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csrf_exempt()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csrf/#django.views.decorators.csrf.csrf_protect\" title=\"django.views.decorators.csrf.csrf_protect\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">csrf_protect()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csrf/#django.views.decorators.csrf.ensure_csrf_cookie\" title=\"django.views.decorators.csrf.ensure_csrf_cookie\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">ensure_csrf_cookie()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/csrf/#django.views.decorators.csrf.requires_csrf_token\" title=\"django.views.decorators.csrf.requires_csrf_token\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">requires_csrf_token()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/howto/error-reporting/#django.views.decorators.debug.sensitive_variables\" title=\"django.views.decorators.debug.sensitive_variables\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sensitive_variables()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/howto/error-reporting/#django.views.decorators.debug.sensitive_post_parameters\" title=\"django.views.decorators.debug.sensitive_post_parameters\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">sensitive_post_parameters()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.gzip.gzip_page\" title=\"django.views.decorators.gzip.gzip_page\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">gzip_page()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.condition\" title=\"django.views.decorators.http.condition\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">condition()</span></code></a></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">conditional_page()</span></code></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.etag\" title=\"django.views.decorators.http.etag\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">etag()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.last_modified\" title=\"django.views.decorators.http.last_modified\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">last_modified()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.require_http_methods\" title=\"django.views.decorators.http.require_http_methods\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">require_http_methods()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.require_GET\" title=\"django.views.decorators.http.require_GET\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">require_GET()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.require_POST\" title=\"django.views.decorators.http.require_POST\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">require_POST()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.http.require_safe\" title=\"django.views.decorators.http.require_safe\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">require_safe()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.vary.vary_on_cookie\" title=\"django.views.decorators.vary.vary_on_cookie\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">vary_on_cookie()</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.vary.vary_on_headers\" title=\"django.views.decorators.vary.vary_on_headers\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">vary_on_headers()</span></code></a></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">xframe_options_deny()</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">xframe_options_sameorigin()</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">xframe_options_exempt()</span></code></p></li>\n</ul>\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\">django.views.decorators.cache</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">never_cache</span>\n\n\n<span class=\"nd\">@never_cache</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_sync_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n\n\n<span class=\"nd\">@never_cache</span>\n<span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_async_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/utils/#django.utils.decorators.method_decorator\" title=\"django.utils.decorators.method_decorator\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">method_decorator()</span></code></a> can be used with asynchronous\nmethods, including <code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">def</span></code> view handlers. Note, though, that if\ndecorating <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/class-based-views/base/#django.views.generic.base.View.dispatch\" title=\"django.views.generic.base.View.dispatch\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">dispatch()</span></code></a> on a <code class=\"docutils literal notranslate\"><span class=\"pre\">View</span></code> with\nasynchronous handlers, you will need to override <code class=\"docutils literal notranslate\"><span class=\"pre\">dispatch</span></code> to make it\n<code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">def</span></code> as well:</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=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyClass</span><span class=\"p\">(</span><span class=\"n\">View</span><span class=\"p\">):</span>\n    <span class=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">never_cache</span><span class=\"p\">)</span>\n    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">dispatch</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">dispatch</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n\n    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">post</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>Here, because we are decorating <code class=\"docutils literal notranslate\"><span class=\"pre\">dispatch</span></code>, rather than the individual\nhandler methods, we need to make <code class=\"docutils literal notranslate\"><span class=\"pre\">dispatch</span></code> asynchronous so that\n<code class=\"docutils literal notranslate\"><span class=\"pre\">method_decorator</span></code> can correctly mark the resulting method as a coroutine\nfunction.</p>\n</section>\n<section id=\"queries-the-orm\">\n<h3>查询与 ORM<a class=\"heading-anchor\" href=\"#queries-the-orm\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>With some exceptions, Django can run ORM queries asynchronously:</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=\"k\">async</span> <span class=\"k\">for</span> <span class=\"n\">author</span> <span class=\"ow\">in</span> <span class=\"n\">Author</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">name__startswith</span><span class=\"o\">=</span><span class=\"s2\">&quot;A&quot;</span><span class=\"p\">):</span>\n    <span class=\"n\">book</span> <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"n\">author</span><span class=\"o\">.</span><span class=\"n\">books</span><span class=\"o\">.</span><span class=\"n\">afirst</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>详细的说明可以在 <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/db/queries/#async-queries\"><span class=\"std std-ref\">异步查询</span></a> 中找到，简而言之：</p>\n<ul class=\"simple\">\n<li><p>所有引发 SQL 查询的 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> 方法都有一个以  <code class=\"docutils literal notranslate\"><span class=\"pre\">a</span></code> 为前缀的异步变体。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">async</span> <span class=\"pre\">for</span></code> 在所有的查询集上都得到支持（包括 <code class=\"docutils literal notranslate\"><span class=\"pre\">values()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">values_list()</span></code> 的输出结果）。</p></li>\n</ul>\n<p>Asynchronous model methods that use the database are also supported:</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=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_book</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"n\">book</span> <span class=\"o\">=</span> <span class=\"n\">Book</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n    <span class=\"k\">await</span> <span class=\"n\">book</span><span class=\"o\">.</span><span class=\"n\">asave</span><span class=\"p\">(</span><span class=\"n\">using</span><span class=\"o\">=</span><span class=\"s2\">&quot;secondary&quot;</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_book_with_tags</span><span class=\"p\">(</span><span class=\"n\">tags</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"n\">book</span> <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"n\">Book</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">acreate</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n    <span class=\"k\">await</span> <span class=\"n\">book</span><span class=\"o\">.</span><span class=\"n\">tags</span><span class=\"o\">.</span><span class=\"n\">aset</span><span class=\"p\">(</span><span class=\"n\">tags</span><span class=\"p\">)</span>\n</code></pre></div>\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<p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/databases/#persistent-database-connections\"><span class=\"std std-ref\">Persistent database connections</span></a>, set\nvia the <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CONN_MAX_AGE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">CONN_MAX_AGE</span></code></a> setting, should also be disabled in async mode.\nInstead, use your database backend's built-in connection pooling if available,\nor investigate a third-party connection pooling option if required. As in\nsynchronous Django, concurrent requests in a single process share that pool, so\nsize it to the target in-flight query concurrency.</p>\n</section>\n<section id=\"performance\">\n<span id=\"async-performance\"></span><h3>性能<a class=\"heading-anchor\" href=\"#performance\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>When running in a mode that does not match the view (e.g. an async view under\nWSGI, or a traditional sync view under ASGI), Django must emulate the other\ncall style to allow your code to run. The per-call cost of this adaptation is\nsmall: tens of microseconds in the in-request ASGI path, where the running\nevent loop is reused, and a few hundred microseconds in the cold-start path\nused by management commands, background tasks, and scripts. Against typical\nrequest times measured in milliseconds, this is rarely visible in itself, but\ncan become so under GIL contention as the number of active threads grows.</p>\n<p>If you find yourself wrapping individual rows or operations in a tight loop,\nrestructure your code so the loop runs inside a single <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>\n(or <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>) crossing. The per-call cost of the context switch is\nthen spread across the whole loop and effectively disappears.</p>\n<p>The same per-call adaptation cost applies to middleware. Django will attempt to\nminimize the number of context-switches between sync and async. If you have an\nASGI server, but all your middleware and views are synchronous, it will switch\njust once, before it enters the middleware stack.</p>\n<p>However, if you put synchronous middleware between an ASGI server and an\nasynchronous view, it will have to switch into sync mode for the middleware and\nthen back to async mode for the view. Django will also hold the sync thread\nopen for middleware exception propagation. For request/response views that hit\nthe ORM and return, this is not usually a meaningful penalty. It matters most\nwhen you are using ASGI for high in-process concurrency over non-ORM I/O (for\nexample upstream HTTP fan-out, server-sent events, or other long-lived\nrequests), where the extra thread per request caps that concurrency.</p>\n<p>你应该执行性能测试来观察 ASGI 和 WSGI 对你的代码有什么影响。在一些案例中，即使对于 ASGI 下的纯同步代码库，性能也可能会有所提高，因为请求处理代码仍然全部异步执行。通常，只有当项目有异步代码时，才需要开启 ASGI 模式。</p>\n</section>\n<section id=\"handling-disconnects\">\n<span id=\"async-handling-disconnect\"></span><h3>处理断开连接<a class=\"heading-anchor\" href=\"#handling-disconnects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>对于长时间运行的请求，在视图返回响应之前，客户端可能会断开连接。在这种情况下，视图会引发一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">asyncio.CancelledError</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=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Do some work</span>\n        <span class=\"o\">...</span>\n    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n        <span class=\"c1\"># Handle disconnect</span>\n        <span class=\"k\">raise</span>\n</code></pre></div>\n<p>你还可以在流式响应中 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/request-response/#request-response-streaming-disconnect\"><span class=\"std std-ref\">处理客户端的断开连接</span></a>。</p>\n</section>\n</section>\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<dl class=\"std envvar\">\n<dt class=\"sig sig-object std\" id=\"envvar-DJANGO_ALLOW_ASYNC_UNSAFE\">\n<span class=\"sig-name descname\"><span class=\"pre\">DJANGO_ALLOW_ASYNC_UNSAFE</span></span><a class=\"heading-anchor\" href=\"#envvar-DJANGO_ALLOW_ASYNC_UNSAFE\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>Certain key parts of Django are not able to operate safely in an async\nenvironment, as they have global state that is not coroutine-aware. These parts\nof Django are classified as &quot;async-unsafe&quot;, and are protected from execution in\nan async environment. The synchronous API of the ORM is the main example, but\nthere are other parts that are also protected in this way.</p>\n<p>如果你试着从有运行事件循环的线程中运行这部分中的任何一个，你会得到一个 <a class=\"reference internal\" href=\"/zh-hans/6.1/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>在运行你的 Django 代码环境中你可以使用异步上下文语境。例如， <a class=\"reference external\" href=\"https://jupyter.org/\">Jupyter</a> 笔记本和 <a class=\"reference external\" href=\"https://ipython.org\">IPython</a> 互动环境都是明显地提供了一种激活事件循环，所以与异步 APIs 互动更容易。</p>\n<p>如果你正在使用 IPython shell，你可以通过运行以下命令来禁用这个事件循环：</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code>%autoawait<span class=\"w\"> </span>off\n</code></pre></div>\n<p>作为 IPython 提示符下的命令。这将允许你运行同步代码，而不会生成 <a class=\"reference internal\" href=\"/zh-hans/6.1/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> 错误；但是，你也无法 <code class=\"docutils literal notranslate\"><span class=\"pre\">await</span></code> 异步 API。要重新启用事件循环，请运行：</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code>%autoawait<span class=\"w\"> </span>on\n</code></pre></div>\n<p>如果你在除了 IPython 之外的环境中（或者因某些原因无法在 IPython 中关闭 <code class=\"docutils literal notranslate\"><span class=\"pre\">autoawait</span></code>），并且你可以 <em>确定</em> 代码不会同时运行，而且你 <em>绝对</em> 需要从异步上下文中运行同步代码，那么您可以通过将 <span class=\"target\" id=\"index-2\"></span><a class=\"reference internal\" href=\"#envvar-DJANGO_ALLOW_ASYNC_UNSAFE\"><code class=\"xref std std-envvar docutils literal notranslate\"><span class=\"pre\">DJANGO_ALLOW_ASYNC_UNSAFE</span></code></a> 环境变量设置为任何值来禁用警告。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>如果启用此选项并且对 Django 的异步不安全部分进行并发访问，可能会导致数据丢失或损坏。请非常小心，不要在生产环境中使用此选项。</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=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">os</span>\n\n<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=\"extlink-pypi 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\n<span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_data</span><span class=\"p\">():</span> <span class=\"o\">...</span>\n\n\n<span class=\"n\">sync_get_data</span> <span class=\"o\">=</span> <span class=\"n\">async_to_sync</span><span class=\"p\">(</span><span class=\"n\">get_data</span><span class=\"p\">)</span>\n\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\">get_other_data</span><span class=\"p\">():</span> <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> is essentially a more powerful version of the\n<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> function in Python's standard library. As well as ensuring\nthreadlocals work, it also enables the <code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive</span></code> mode of\n<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> when that wrapper is used below it. In the cold path\n(no running event loop) it pays the cost of starting a fresh event loop, like\n<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>; when an event loop is already running (the in-request ASGI\ncase), the running loop is reused and the cost drops accordingly.</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\">True</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> <span class=\"n\">thread_sensitive</span><span class=\"o\">=</span><span class=\"kc\">False</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\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>\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=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<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive=False</span></code>：同步函数将在一个全新的线程中运行，该线程一旦完成，将会关闭。</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<p>Within a single request, multiple <code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive</span></code> calls serialize on that\nrequest's worker thread, but each request gets its own per-context worker, so\nconcurrent requests do <em>not</em> serialize against each other. This mirrors\nDjango's connection-per-thread model, and the same constraint applies in other\nasync database libraries, where concurrent queries on a single connection\nserialize on a lock. To support more concurrent requests, increase the\nconnection pool size accordingly rather than disabling <code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive</span></code>.</p>\n<p>在实际应用中，这意味着在调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code> 时，你不应该传递数据库 <code class=\"docutils literal notranslate\"><span class=\"pre\">connection</span></code> 对象的特性。这样做将触发线程安全检查：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"go\"># DJANGO_SETTINGS_MODULE=settings.py python -m asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><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<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">connection</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># In an async context so you cannot use the database directly:</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span>\n<span class=\"go\">django.core.exceptions.SynchronousOnlyOperation: You cannot call this from</span>\n<span class=\"go\">an async context - use a thread or sync_to_async.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Nor can you pass resolved connection attributes across threads:</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">await</span> <span class=\"n\">sync_to_async</span><span class=\"p\">(</span><span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">)()</span>\n<span class=\"go\">django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread</span>\n<span class=\"go\">can only be used in that same thread. The object with alias &#39;default&#39; was</span>\n<span class=\"go\">created in thread id 4371465600 and this is thread id 6131478528.</span>\n</code></pre></div>\n<p>相反，您应该将所有数据库访问封装在一个帮助函数中，该函数可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code> 调用，而不依赖于调用代码中的连接对象。</p>\n</section>\n</section>","rootId":"asynchronous-support","toc":[{"title":"异步视图","anchor":"async-views","children":[{"title":"装饰器","anchor":"decorators","children":[]},{"title":"查询与 ORM","anchor":"queries-the-orm","children":[]},{"title":"性能","anchor":"performance","children":[]},{"title":"处理断开连接","anchor":"handling-disconnects","children":[]}]},{"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/6.1/topics/"}],"prev":{"docname":"topics/checks","title":"系统检查框架","url":"/zh-hans/6.1/topics/checks/"},"next":{"docname":"topics/tasks","title":"Django's Tasks framework","url":"/zh-hans/6.1/topics/tasks/"},"formats":{"html":"/zh-hans/6.1/topics/async/","markdown":"/zh-hans/6.1/topics/async.md","json":"/zh-hans/6.1/topics/async.json"},"source":"https://github.com/django/django/blob/stable/6.1.x/docs/topics/async.txt","official":"https://docs.djangoproject.com/zh-hans/6.1/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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}