비동기/대기

Async/await

컴퓨터 프로그래밍에서 비동기/대기 패턴은 비동기 비블록 함수를 일반적인 동기 함수와 유사한 방식으로 구조화할 수 있도록 하는 많은 프로그래밍 언어의 구문적 기능입니다.이것은 의미론적으로 코루틴의 개념과 관련이 있고 종종 유사한 기술을 사용하여 구현되며, 주로 프로그램이 장기 실행, 비동기 작업이 완료되기를 기다리는 동안 다른 코드를 실행할 기회를 제공하기 위한 것이다.이 기능은 C# 5.0, C++20, Python 3.5, F#, Hack, Julia, Dart, Kotlin 1.1, Rust 1.39,[1] Nim 0.9.4,[2] JavaScript ES2017, Swift 5.5[3] [4]Zig에서 볼 수 있으며 확장, 베타 버전 및 특정 Scala [5]구현에 대한 실험적인 작업이 있습니다.

역사

F#은 2007년 [6]버전 2.0에서 대기점이 있는 비동기 워크플로우를 추가했습니다.이는 C#[7]에 추가된 비동기/대기 메커니즘에 영향을 미칩니다.

Microsoft는 비동기 CTP(2011)에서 최초로 비동기/대기 기능을 탑재한 C# 버전을 출시했습니다.그리고 이후 C#5(2012)[8]에서 정식 발매되었습니다.

Haskell 수석 개발자인 Simon Marlow는 2012년에 [9]비동기 패키지를 만들었습니다.

Python은 2015년 버전[10] 3.5에서 비동기/대기 지원을 추가했으며 2개의 새로운 키워드를 추가했다.async그리고.await.

TypeScript는 2015년에 [11]버전 1.7에서 비동기/대기 지원이 추가되었습니다.

Javascript는 ECMAScript 2017 JavaScript 에디션의 일부로 2017년에 비동기/대기 지원을 추가하였습니다.

2019년 버전 1.39.0에서 비동기/대기 지원 추가(키워드 1개 추가)async게으른 평가가 [13]패턴을 기다리고 있습니다.

C++는 3개의 새로운 키워드를 사용하여 버전 20에서 비동기/대기 지원 추가co_return,co_await,co_yield.

Swift는 2021년에 버전 5.5에서 비동기/대기 지원 추가, 새로운 키워드 2개 추가async그리고.await이것은 액터 모델의 구체적인 구현과 함께 발표되었습니다.actorasync/sync/sync를 사용하여 외부에서[14] 각 액터에 대한 접근을 중개합니다.

예 C#

다음 C# 함수는 URI에서 리소스를 다운로드하고 리소스 길이를 반환합니다.이 함수는 다음 비동기/대기 패턴을 사용합니다.

일반의 비동기 작업< >인트> Find Page Size Async(URI uri)  {     변화하다 고객 = 신규 Http Client();     바이트[] 데이터. = 기다리다 고객.GetByte Array Async(uri);     돌아가다 데이터..길이; } 
  • 일단은async키워드는 C#에 대해 메서드가 비동기임을 나타냅니다.즉, 임의의 수의 C#은await표현하고 결과를 약속에 구속합니다.
  • 반환 유형,Task<T>는 약속의 개념에 대한 C#의 아날로그이며, 여기에는 type의 결과값이 지정되어 있습니다.int.
  • 이 메서드를 호출할 때 실행하는 첫 번째 식은 다음과 같습니다.new HttpClient().GetByteArrayAsync(uri)이것은 다른 비동기 방식입니다.Task<byte[]>이 메서드는 비동기 방식이기 때문에 반환하기 전에 전체 데이터 배치를 다운로드하지 않습니다.대신 백그라운드스레드 등의 비블로킹메커니즘을 사용하여 다운로드 프로세스를 시작하고 해결되지 않은 거부되지 않은 것을 즉시 반환합니다.Task<byte[]>이 기능으로 이동합니다.
  • 를 사용하여await에 부가된 키워드Task이 함수는 즉시 다음 명령을 반환합니다.Task<int>발신자는 필요에 따라 다른 처리를 계속할 수 있습니다.
  • 한번만GetByteArrayAsync()다운로드가 종료되면, 이 조작으로 해결됩니다.Task다운로드한 데이터와 함께 반환되었습니다.이로 인해 콜백이 트리거되어 원인이 됩니다.FindPageSizeAsync()그 값을 할당하여 실행을 계속하다data.
  • 마지막으로 메서드가 반환됩니다.data.Length는 배열의 길이를 나타내는 단순한 정수입니다.컴파일러는 이 문제를 해결하도록 재해석합니다.Task이 값은 이전에 반환되어 메서드 호출기에서 콜백을 트리거하여 해당 길이 값으로 작업을 수행하도록 합니다.

비동기/대기 기능을 사용하는 함수는 다음과 같이 사용할 수 있습니다.await각 표현은 같은 방법으로 처리됩니다(단, 약속은 첫 번째 대기시에만 발신자에게 반환되고 다른 모든 대기자는 내부 콜백을 사용합니다).또한 함수는 직접 약속 객체를 보유하고 다른 처리를 먼저 수행할 수 있으며(다른 비동기 태스크의 시작을 포함), 결과가 필요할 때까지 약속 대기 시간을 지연시킬 수 있습니다.약속이 있는 함수에는 약속 집계 방식도 있어 여러 약속을 한 번에 또는 특정 패턴(C#의 약속 등)으로 대기할 수 있습니다.Task.WhenAll()값어치가 없습니다.Task인수의 모든 작업이 해결되면 해결됩니다).또한 많은 약속 유형에는 여러 결과 콜백을 설정하거나 특정 장기 실행 태스크의 진행 상황을 검사할 수 있는 등 비동기/대기 패턴이 일반적으로 사용하는 기능 이외의 추가 기능이 있습니다.

특정 C#의 경우 및 이 언어 기능을 가진 다른 많은 언어에서 비동기/대기 패턴은 언어 런타임의 핵심 부분이 아니라 컴파일 시 람다 또는 연속과 함께 구현됩니다.예를 들어 C# 컴파일러는 위의 코드를 IL 바이트 코드 형식으로 변환하기 전에 다음과 같은 형식으로 변환합니다.

일반의 작업< >인트> Find Page Size Async(URI uri)  {     변화하다 고객 = 신규 Http Client();     작업< >바이트[ ] > 데이터 태스크 = 고객.GetByte Array Async(uri);     작업< >인트> 애프터 데이터 태스크 = 데이터 태스크.계속하다.와 함께((original Task(원래 태스크)) => {         돌아가다 original Task(원래 태스크).결과.길이;     });     돌아가다 애프터 데이터 태스크; } 

이 때문에 인터페이스 메서드가 약속 개체를 반환해야 하지만 그 자체로는 반환할 필요가 없는 경우await본문에서는 비동기 태스크를 대기하기 위해async수식자 중 하나이며 대신 약속 개체를 직접 반환할 수 있습니다.예를 들어, 함수는 어떤 결과값(C# 등)으로 즉시 해결되는 약속을 제공할 수 있습니다.Task.FromResult()또는 다른 방법의 약속(: 과부하로 지연되는 경우)을 반환할 수도 있습니다.

단, 이 기능의 중요한 경고 중 하나는 코드가 기존의 블로킹코드와 유사하지만 코드는 실제로는 비블로킹이며 잠재적으로 멀티스레드라는 것입니다.즉, 다수의 인터럽트 이벤트가 타겟팅된 약속을 기다리는 동안 발생할 수 있습니다.await해결할 수 있습니다.예를 들어, 다음 코드는 항상 다음 코드 없이 블로킹모델에 성공합니다await에서는, 에러에 의해서, 에러 메세지가 송신되는 사이에,await따라서 그 아래에서 공유 상태가 변경되는 경우가 있습니다.

변화하다 a = .a; 변화하다 고객 = 신규 Http Client(); 변화하다 데이터. = 기다리다 고객.GetByte Array Async(uri); 디버깅.주장하다(a == .a); // state.a 값이 변경되었을 수 있으므로 장애가 발생할 수 있습니다.                             // 잠재적으로 개입할 수 있는 이벤트의 핸들러. 돌아가다 데이터..길이; 

인 F#

F#은 버전 2.0에서 [15]비동기 워크플로우를 추가했습니다.비동기 워크플로우는 CE(계산식)로 구현됩니다.특별한 컨텍스트를 지정하지 않고 정의할 수 있습니다(예:async(C#)에 있습니다.F# 비동기 워크플로우는 비동기 작업을 시작하기 위해 키워드에 bang(!)을 추가합니다.

다음 비동기 함수는 비동기 워크플로우를 사용하여 URL에서 데이터를 다운로드합니다.

허락하다 비동기 Sum Page 사이즈 (소변기: #인식하다< >URI>) : 비동기< >인트> = 비동기 {     사용하다 http Client = 신규 Http Client()     렛츠! 페이지 =          소변기         > .지도(http Client.GetStringAsync >> 비동기.태스크 대기)         > 비동기.병렬     돌아가다 페이지 > .접다 (재밌어요 어큐뮬레이터 현재의 -> 현재의.길이 + 어큐뮬레이터) 0 } 

인 C#

C#의 비동기/대기 패턴은 버전 5.0에서 사용할 수 있습니다.Microsoft에서는 이를 Task-Based Asynchronous Pattern(TAP;[16] 태스크베이스 비동기 패턴)이라고 부릅니다.다음 중 하나를 반환하려면 비동기 메서드가 필요합니다.void,Task,Task<T>, 또는ValueTask<T>(후자 버전 7.0만 해당).반환되는 비동기 메서드void이벤트 핸들러를 대상으로 하고 있습니다.대부분의 경우 동기 메서드가 반환됩니다.void,돌아오는Task보다 직관적인 예외 [17]처리가 가능하기 때문에 권장됩니다.

를 사용하는 방법await와 함께 선언해야 합니다.async키워드를 지정합니다.type의 반환값이 있는 메서드Task<T>, 로 선언된 메서드async에 할당할 수 있는 유형의 반환문이 있어야 합니다.T대신Task<T>; 컴파일러는 값을 에 랩합니다.Task<T>포괄적인.할 수도 있다await반환 유형을 가진 메서드Task또는Task<T>없는 것으로 선언되어 있다async.

다음 비동기 방식은 다음을 사용하여 URL에서 데이터를 다운로드합니다.await이 메서드는 각 URI에 대해 작업을 발행한 후 를 완료해야 하기 때문에await키워드를 지정하면 마지막 리소스가 완료될 때까지 기다렸다가 다음 리소스를 동시에 로드할 수 있습니다.

일반의 비동기 작업< >인트> Sum Page Sizes Async(ICollection(ICollection)< >URI> 소변기)  {     변화하다 고객 = 신규 Http Client();     인트  = 0;     변화하다 로드우리 태스크 = 신규 목록.< >작업< >바이트[ ] > > ( ) ;      앞지르다 (변화하다 uri  소변기)     {         변화하다 로드유리 태스크 = 고객.GetByte Array Async(uri);         로드우리 태스크.더하다(로드유리 태스크 );     }      앞지르다 (변화하다 로드유리 태스크  로드우리 태스크)     {         상태 텍스트.본문 = $" {total}바이트를 찾았습니다...";         변화하다 자원바이트 수 = 기다리다 로드유리 태스크;          += 자원바이트 수.길이;     }      상태 텍스트.본문 = $"합계 {total}바이트 발견";      돌아가다 ; } 

인스칼라

스칼라에 대한 실험적인 스칼라 비동기 확장에서는await통상적인 [5]방법과는 달리 동작하지 않지만, 는 「실행」입니다.또한 메서드를 비동기식으로 마킹해야 하는 C# 5.0과는 달리 Scala-async에서는 코드 블록이 비동기식 "콜"로 둘러싸여 있습니다.

구조

스칼라 비동기에서는async는 실제로 Scala 매크로를 사용해 실장되어 컴파일러가 다른 코드를 발신해 유한 상태의 머신을 실장한다(모나딕 실장보다 효율적이지만 수작업으로 쓰기에는 그다지 편리하지 않다).

비동기 구현을 포함한 다양한 구현을 지원하기 위한 Scala-async 계획이 있습니다.

Python의 경우

Python 3.5(2015)[18]는 PEP 492(https://www.python.org/dev/peps/pep-0492/))에 설명된 대로 비동기/비동기 지원을 추가했습니다.

수입품 비동기  비동기 방어하다 주된():     인쇄물("안녕하세요")     기다리다 비동기.수면.(1)     인쇄물("세계")  비동기.달려.(주된()) 

자바스크립트

JavaScript의 wait 연산자는 비동기 함수 내부에서만 사용할 수 있습니다.파라미터가 약속일 경우 약속이 해결되면 비동기 함수의 실행이 재개됩니다(약속이 거부되지 않는 한 일반 JavaScript 예외 처리로 처리할 수 있는 오류가 발생합니다).파라미터가 확약이 아닌 경우 파라미터 자체가 [19]즉시 반환됩니다.

많은 라이브러리는 네이티브 JavaScript 약속 사양과 일치하는 한 wait에서도 사용할 수 있는 약속 개체를 제공합니다.그러나 jQuery 3.0까지는 jQuery 라이브러리의 약속이 Promise/A+와 호환되지 않았습니다.[20]

다음은 예를 제시하겠습니다(이 문서에서 수정[21]).

비동기 기능. create New Doc() {   허락하다 대답 = 기다리다 db.포스트.({}); // 새 문서 게시   돌아가다 db.얻다(대답.아이디); // ID로 검색 }  비동기 기능. 주된() {   해라 {     허락하다 문서 = 기다리다 create New Doc();     콘솔.로그.(문서);   } 또 만나 (에러) {     콘솔.로그.(에러);   } } 주된(); 

Node.js 버전8에는 [22]표준 라이브러리 콜백 기반의 메서드를 약속대로 사용할 수 있는 유틸리티가 포함되어 있습니다.

C++의 경우

C++에서는 wait(C++에서는 co_await로 명명됨)이 버전 [23]20으로 공식적으로 병합되었습니다.지원, coroutines 및 다음과 같은 키워드co_awaitGCCMSVC 컴파일러에서 사용할 수 있으며 Clang은 부분적으로 지원됩니다.

std::promise 및 std::future는 대기 대상인 것처럼 보이지만 코루틴에서 반환되어 co_await를 사용하여 대기할 필요가 있는 기계는 모두 구현해야 합니다.프로그래머는 다음과 같은 많은 공개 멤버 기능을 구현해야 합니다.await_ready,await_suspend,그리고.await_resume타입을 대기시키기 위해 리턴 타입으로 설정합니다.자세한 내용은 cpp reference를 참조하십시오.

#실패하다 <iostream> #실패하다 「Custom Awaitable Task.h"  사용. 네임스페이스 표준;  Custom Awaitable 태스크< >인트> 더하다(인트 a, 인트 b) {     인트 c = a + b;     co_return(반환) c; }  Custom Awaitable 태스크< >인트> 시험() {     인트 리트 = 코_리모트 더하다(1, 2);     외치다 << > "return' << > 리트 << > ;     co_return(반환) 리트; }  인트 주된() {     자동 작업 = 시험();      돌아가다 0; } 

주식회사

C언어로 wait/async에 대한 공식 지원은 아직 없습니다.s_task 등의 일부 Coroutine 라이브러리는 매크로를 사용하여 키워드 wait/async를 시뮬레이션합니다.

#실패하다 <stdio.h> #실패하다 "s_tasks_task.h"  // 태스크용 스택메모리 정의 인트 g_stack_main[64 * 1024 / 크기(인트)]; 인트 g_stack0[64 * 1024 / 크기(인트)]; 인트 g_stack1[64 * 1024 / 크기(인트)];  무효 서브태스크(__syslogc__, 무효* arg) {     인트 i;     인트 n = (인트)(size_t)arg;     위해서 (i = 0; i < > 5; ++i) {         인쇄물("태스크 %d, 지연초 = %d, i = %d\n", n, n, i);         s_task_sleep(__param__, n * 1000);         //s_task_yield(_sysk__);     } }  무효 메인 태스크(__syslogc__, 무효* arg) {     인트 i;      // 2개의 서브패키지 작성     s_task_작성(g_stack0, 크기(g_stack0), 서브태스크, (무효*)1);     s_task_작성(g_stack1, 크기(g_stack1), 서브태스크, (무효*)2);      위해서 (i = 0; i < > 4; ++i) {         인쇄물("task_main arg = %p, i = %d\n", arg, i);         s_task_수익률(__param__);     }      // 서브패킷이 종료될 때까지 기다립니다.     s_task_module(__param__, g_stack0);     s_task_module(__param__, g_stack1); }  인트 주된(인트 argc, * argv) {      s_task_init_system();      //메인 태스크 생성     s_task_작성(g_stack_main, 크기(g_stack_main), 메인 태스크, (무효*)(size_t)argc);     s_task_module(__param__, g_stack_main);     인쇄물("모든 작업이 끝났습니다.\n");     돌아가다 0; } 

Perl 5의 경우

미래:비동기 Await 모듈은 2018년 [24]9월에 Perl Foundation 조성 대상이었습니다.

녹슬어 있음

2019년 11월 7일, [25]Rust의 안정판으로 비동기/대기판이 발매되었습니다.비동기 기능은 Rust desugar에서 Future 특성을 구현하는 값을 반환하는 플레인 함수로 기능합니다.현재는 유한 상태 [26]기계로 구현되어 있습니다.

// crate Cargo.toml에서는 의존관계 섹션에 "dependencies" = "0.3.0"필요합니다.// "std" 라이브러리에는 현재 실행자가 없습니다.// "fn asyn_add_one ( num : 32 ) - < future >와 같은 것에 디스거합니다.출력 = u32 > ' async fn _ add _ one ( num : u32) -> u32 { num + 1 } async fn example _ task() { let num = add _ one ( 5 . task ) ; println ! ( " 5 + 1 = { } , number } ) ) ) ) ) } fnumber ) 、 fnumber )  number ) 、 number ) 、 、 、 number ) 、 number )  let future = example_task(); // 'Future'는 Javascript와 달리 실제로 폴링할 때만 실행됩니다. 선물:: vlock_on(미래); }

인스위프트

SE-0296(https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md))의 설명에 따라 Swift 5.5(스위프트)[27]에서는 비동기/스위치의 지원이 추가되었습니다.

기능하다 get Number(번호)() 비동기 던지다 -> 내부 {     해라 기다리다 작업.수면.(나노초: 1_000_000_000)     돌아가다 42 }  작업 {     허락하다 첫번째 = 해라 기다리다 get Number(번호)()     허락하다 둘째 = 해라 기다리다 get Number(번호)()     인쇄물(첫번째 + 둘째) } 

장점과 비판

이를 지원하는 언어에서 비동기/대기 패턴의 중요한 장점은 비동기식 논블로킹코드를 최소한의 오버헤드로 작성할 수 있으며 기존의 동기식 블로킹코드와 거의 비슷하다는 것입니다.특히, 대기(wait)가 메시지 전달 프로그램에서 비동기 코드를 작성하는 가장 좋은 방법이라는 주장이 제기되었습니다. 특히, 차단 코드에 가까운 것, 가독성 및 최소한의 보일러 플레이트 코드가 대기 혜택으로 [28]언급되었습니다.그 결과, 비동기/대기 기능을 사용하면 대부분의 프로그래머가 자신의 프로그램에 대해 쉽게 추론할 수 있으며, 이를 필요로 하는 응용 프로그램에서 보다 우수하고 강력한 논블로킹 코드를 촉진하는 경향이 있습니다.이러한 애플리케이션은 그래픽 사용자 인터페이스를 제공하는 프로그램부터 게임이나 재무 애플리케이션 등 대규모로 확장 가능한 서버 측 프로그램까지 다양합니다.

wait를 비판할 때 wait는 주변 코드도 비동기화하는 경향이 있는 반면, 코드의 전염성(때로는 "좀비 바이러스"와 비교됨)은 모든 종류의 비동기 프로그래밍에 고유하기 때문에 이러한 점에서 [17]wait는 고유하지 않다는 주장이 제기되어 왔다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ "Announcing Rust 1.39.0". Retrieved 2019-11-07.
  2. ^ "Version 0.9.4 released - Nim blog". Retrieved 2020-01-19.
  3. ^ "Concurrency — The Swift Programming Language (Swift 5.5)". docs.swift.org. Retrieved 2021-09-28.
  4. ^ "Zig Language Reference".
  5. ^ a b "Scala Async". GitHub. Retrieved 20 October 2013.
  6. ^ Syme, Don; Petricek, Tomas; Lomov, Dmitry (2011). The F# Asynchronous Programming Model. Springer Link. Lecture Notes in Computer Science. Vol. 6539. pp. 175–189. doi:10.1007/978-3-642-18378-2_15. ISBN 978-3-642-18377-5. Retrieved 2021-04-29.
  7. ^ "The Early History of F#, HOPL IV". ACM Digital Library. Retrieved 2021-04-29.
  8. ^ Hejlsberg, Anders. "Anders Hejlsberg: Introducing Async – Simplifying Asynchronous Programming". Channel 9 MSDN. Microsoft. Retrieved 5 January 2021.
  9. ^ "async: Run IO operations asynchronously and wait for their results". Hackage.
  10. ^ "What's New In Python 3.5 — Python 3.9.1 documentation". docs.python.org. Retrieved 5 January 2021.
  11. ^ Gaurav, Seth (30 November 2015). "Announcing TypeScript 1.7". TypeScript. Microsoft. Retrieved 5 January 2021.
  12. ^ Matsakis, Niko. "Async-await on stable Rust! Rust Blog". blog.rust-lang.org. Rust Blog. Retrieved 5 January 2021.
  13. ^ "Rust Gets Zero-Cost Async/Await Support in Rust 1.39".
  14. ^ "Concurrency — the Swift Programming Language (Swift 5.6)".
  15. ^ "Introducing F# Asynchronous Workflows".
  16. ^ "Task-based asynchronous pattern". Microsoft. Retrieved 28 September 2020.
  17. ^ a b Stephen Cleary, Async/Awit - 비동기 프로그래밍의 베스트 프랙티스
  18. ^ "Python Release Python 3.5.0".
  19. ^ "await - JavaScript (MDN)". Retrieved 2 May 2017.
  20. ^ "jQuery Core 3.0 Upgrade Guide". Retrieved 2 May 2017.
  21. ^ "Taming the asynchronous beast with ES7". Retrieved 12 November 2015.
  22. ^ Foundation, Node.js. "Node v8.0.0 (Current) - Node.js". Node.js.
  23. ^ "ISO C++ Committee announces that C++20 design is now feature complete". 25 February 2019.
  24. ^ "September 2018 Grant Votes - The Perl Foundation". news.perlfoundation.org. Retrieved 2019-03-26.
  25. ^ Matsakis, Niko. "Async-await on stable Rust!". Rust Blog. Retrieved 7 November 2019.
  26. ^ Oppermann, Philipp. "Async/Await". Retrieved 28 October 2020.
  27. ^ https://www.swift.org/blog/swift-5-5-released/
  28. ^ '벌레 없음' 토끼.메시지 전달 프로그램에서 논블로킹 반환을 처리하는 8가지 방법 CPPCON, 2018