{"title":"비동기 지원","version":"6.0","locale":"ko","docname":"topics/async","url":"/ko/6.0/topics/async/","canonical":"https://djangodocs.dev/ko/6.0/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 (“async”) views, along with an\nentirely async-enabled request stack if you are running under <a class=\"reference internal\" href=\"/ko/6.0/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=\"/ko/6.0/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>모든 뷰는 비동기로 선언될 수있다. 일반적으로 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>async def``를 사용해 뷰의 호출 가능 부분이 coroutine을 반환하도록 하면 된다. 즉, 함수 기반 뷰의 경우 전체 함수에  <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">``</span></a>async def``를, 클래스 기반 뷰는 내부 <a href=\"#id5\"><span class=\"problematic\" id=\"id6\">``</span></a>get()``과 <a href=\"#id7\"><span class=\"problematic\" id=\"id8\">``</span></a>post()``와 같은  HTTP 요청 처리 메서드( <a href=\"#id9\"><span class=\"problematic\" id=\"id10\">``</span></a>__init__()``나 <a href=\"#id11\"><span class=\"problematic\" id=\"id12\">``</span></a>as_view()``가 아닌)에 <a href=\"#id13\"><span class=\"problematic\" id=\"id14\">``</span></a>async def``를 사용하는 것을 의미한다.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">참고</p>\n<p>장고는 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>asgiref.sync.iscoroutinefunction``으로 뷰의 비동기 여부를 검사한다. corutine을 반환하는 별도의 방법을 적용한 경우 <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">``</span></a>asgiref.sync.markcoroutinefunction``을 사용하여 위 함수가 <a href=\"#id5\"><span class=\"problematic\" id=\"id6\">``</span></a>True``를 반환하도록 하자.</p>\n</aside>\n<p>WSGI 서버에서, 비동기 view는 자체 일회성 이벤트 루프에서 실행된다.  문제 없이 비동기 동시성 HTTP 요청과 같은 기능을 사용할 수 있으나 비동기식 스택의 장점은 얻을 수 없다.</p>\n<p>주요 이점은 수백개의 연결을 Python 스레드를 이용하지 않고 서비스를 할 수 있는 것이다.  이는 느린 스트리밍, 긴 폴링과 다른 흥미로운 응답 유형을 사용할 수 있도록 한다.</p>\n<p>이를 이용하고 싶다면, :doc:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>ASGI를 이용하여 Django를 배포해야한다.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">참고</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=\"/ko/6.0/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>“Asynchronous handler adapted for\nmiddleware …”</em>.</p>\n</aside>\n<p>ASGI와 WSGI 모드에서 모두, 연속적으로보다 코드를 동시에 실행하여 비동기식 지원을 안전하게 사용할 수 있다. 외부 API나 데이터 저장소를 다룰 때 특히 유용하다</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> 호출로 wrapping해야 한다. 예:</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>장고의 요소 중 동기 전용 요소를 비동기 뷰에서 호출할 경우 <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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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=\"/ko/6.0/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</section>\n<section id=\"queries-the-orm\">\n<h3>쿼리 &amp; 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>자세한 내용은 :ref:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>async-queries`에서 확인 가능하다. 요약하면:</p>\n<ul class=\"simple\">\n<li><p>SQL 쿼리를 발생시키는 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>QuerySet``의 모든 메서드는 접두사 <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">``</span></a>a``가 붙은 비동기 메서드가 있다.</p></li>\n<li><p>모든 QuerySets(<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>values()``와 <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">``</span></a>values_list()``의 결과 값 포함)에서 <a href=\"#id5\"><span class=\"problematic\" id=\"id6\">``</span></a>async for``가 지원된다.</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>아직 트랜잭션 처리는 비동기로 동작하지 않는다. 코드 중 트랙젝션으로 처리가 필요한 부분에 대해서는 별도 동기 함수로 작성한 다음 :func:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>sync_to_async`를 사용해 호출하자.</p>\n<p><a class=\"reference internal\" href=\"/ko/6.0/ref/databases/#persistent-database-connections\"><span class=\"std std-ref\">Persistent database connections</span></a>, set\nvia the <a class=\"reference internal\" href=\"/ko/6.0/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>Handling disconnects<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>For long-lived requests, a client may disconnect before the view returns a\nresponse. In this case, an <code class=\"docutils literal notranslate\"><span class=\"pre\">asyncio.CancelledError</span></code> will be raised in the\nview. You can catch this error and handle it if you need to perform any\ncleanup:</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>You can also <a class=\"reference internal\" href=\"/ko/6.0/ref/request-response/#request-response-streaming-disconnect\"><span class=\"std std-ref\">handle client disconnects in streaming responses</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 “async-unsafe”, 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>“running event loop”가 있는 스레드에서 이러한 부분을 실행하고자 하면, <a class=\"reference internal\" href=\"/ko/6.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> error가 발생한다. 이 오류를 발생하기 위해서 비동기식 함수 내부에 직접적으로 있을 필요가 없다. 동기식 함수에서 동기식 함수를 직접적으로 호출하면, :func:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>sync_to_async`을 사용하지 않고도 오류가 발생할 수 있다. 비동기식 코드로 선언되었음에도 불구하고, 활성 이벤트 루프가 있는 스레드 안에서 코드는 여전히 실행중이기 때문이다.</p>\n<p>오류가 발생하면, 비동식 컨텍스트에서 문제가 있는 코드를 호출하지 않도록 코드를 수정해야 한다. 대신에, 자체적인 비동기식의 안전하지 않은 함수와 동기식 함수와 통신하는 코드를 작성하고, :func:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>asgiref.sync.sync_to_async`(또는 자체 스레드에서 동기식 코드를 실행하는 다른 방법)을 이용하여 호출한다.</p>\n<p>비동기식 컨텍스트는 django 코드를 실행하는 환경에 의해 부과될 수 있다. 예를 들어, <a class=\"reference external\" href=\"https://jupyter.org/\">Jupyter</a> notebooks and <a class=\"reference external\" href=\"https://ipython.org\">IPython</a> interactive shells 모두 비동기식 API와 상호작용을 더 쉽게 할 수 있도록 투명하게 활성 이벤트 루프를 제공한다.</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=\"/ko/6.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> 에러 없이 실행가능하다. 반면 비동기 API들에 대해서는 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>await``와 함께 사용할 수 없게 된다. 다시 이벤트 루프를 활성화하려면 다음을 실행한다:</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>If you’re in an environment other than IPython (or you can’t turn off\n<code class=\"docutils literal notranslate\"><span class=\"pre\">autoawait</span></code> in IPython for some reason), you are <em>certain</em> there is no chance\nof your code being run concurrently, and you <em>absolutely</em> need to run your sync\ncode from an async context, then you can disable the warning by setting the\n<span class=\"target\" id=\"index-0\"></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> environment variable to any value.</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">경고</p>\n<p>이 옵션을 쓸 수 있게 하고 안전하지 않은 비동기식 django의 부분으로 동시 접속이 있다면, 데이터 손실이나 오염을 입을 수 있다. 매우 주의 해야하고 프로덕션 환경에서 사용하지 않는다.</p>\n</aside>\n<p>파이썬 내에서 수행해야한다면, <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>os.environ``으로 수행한다.:</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> and <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=\"extlink-pypi reference external\" href=\"https://pypi.org/project/asgiref/\">asgiref</a> 패키지는 장고 프로젝트의 일부이며 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>pip``으로 장고를 설치 시 의존 패키지로 자동 설치된다.</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=\"(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=\"(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>동기식 함수는 메인 스레드에서 모두 실행된다고 가정하여 쓰이는 경향이 있어서, :func:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>sync_to_async`는 두 개의 스레딩 모드를 가진다.</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">thread_sensitive=True</span></code> (디폴트): 동기식 함수는 다른 모든``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> 래퍼를 이용하면,  이것이 메인 스레드일 것이다.</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 모드는 특별하고, 같은 스레드의 모든 함수를 실행하기 위해 많은 작업을 수행한다. 그럼에도 불구하고, 메인 스레드에서 올바르게 실행하기 위해 <em>스택에서</em> <code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">async_to_sync`의</span> <span class=\"pre\">*용례를</span> <span class=\"pre\">필요로</span> <span class=\"pre\">하다*.</span> <span class=\"pre\">``asyncio.run()`()</span></code> 또는 유사한 것을 사용한다면,  단일의, 공유되는 스레드의 thread-sensitive 함수를 실행하는 것으로 돌아갈 것이지만, 이는 메인 스레드는 아닐 것이다.</p>\n<p>django에서 필요한 이유는 많은 라이브러리들 중 특히 데이터베이스 어댑터들은, 라이브러리들이 생성된 같은 스레드에 액세스하는 것을 필요로 하기 때문이다. 또한 기존의 많은 django 코드는 같은 스레드에서 모두 실행하는 것을 가정하고, 예를 들어, 미들웨어는 뷰에서 이후에 사용할 것을 위한 것을 요청에 추가한다</p>\n<p>이 코드의 잠재적인 호환성 문제를 내놓는 것 대신에, 존재하는 모든 django 동기식 코드가 같은 스레드에서 실행하고 비동기식 모드와 완전히 호환이 될 수 있도록 이 모드를 추가하기로 선택하였다. 동기식 코드는 항상 호출하는 비동기식 코드와 <em>다른</em> 스레드에 있으므로, 원시 데이터베이스 핸들이나 다른 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\">connection</span></code> 객체의 기능들을 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>sync_to_async()``에 전달해서는 안된다. 전달할 경우 스레드 안정성 검사를 일으킨다.:</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>Rather, you should encapsulate all database access within a helper function\nthat can be called with <code class=\"docutils literal notranslate\"><span class=\"pre\">sync_to_async()</span></code> without relying on the connection\nobject in the calling 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":"Handling disconnects","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":"/ko/6.0/topics/"}],"prev":{"docname":"topics/external-packages","title":"외부 패키지","url":"/ko/6.0/topics/external-packages/"},"next":{"docname":"topics/tasks","title":"Django’s Tasks framework","url":"/ko/6.0/topics/tasks/"},"formats":{"html":"/ko/6.0/topics/async/","markdown":"/ko/6.0/topics/async.md","json":"/ko/6.0/topics/async.json"},"source":"https://github.com/django/django/blob/stable/6.0.x/docs/topics/async.txt","official":"https://docs.djangoproject.com/ko/6.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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}