사실, async / await는 그렇게 마 법적이지 않습니다. 전체 주제는 상당히 광범위하지만 귀하의 질문에 대한 신속하면서도 충분한 답변을 위해 관리 할 수 있다고 생각합니다.
Windows Forms 응용 프로그램에서 간단한 버튼 클릭 이벤트를 해결해 보겠습니다.
public async void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("before awaiting");
await GetSomethingAsync();
Console.WriteLine("after awaiting");
}
나는 그것이 무엇인지에 대해 명시 적으로 이야기 하지 않을 것입니다GetSomethingAsync
지금 돌아 오는 . 이것이 2 초 후에 완료 될 것이라고 가정 해 봅시다.
비동기식의 전통적인 세계에서 버튼 클릭 이벤트 핸들러는 다음과 같습니다.
public void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("before waiting");
DoSomethingThatTakes2Seconds();
Console.WriteLine("after waiting");
}
양식에서 버튼을 클릭하면이 방법이 완료 될 때까지 기다리는 동안 응용 프로그램이 약 2 초 동안 정지 된 것으로 나타납니다. 기본적으로 루프 인 "메시지 펌프"가 차단됩니다.
이 루프는 계속해서 창에 묻습니다. "마우스를 움직이거나 무언가를 클릭 한 것과 같은 일을 한 사람이 있습니까? 무언가를 다시 칠해야합니까? 그렇다면 말 해주세요!" 그런 다음 "무언가"를 처리합니다. 이 루프는 사용자가 "button1"(또는 Windows의 동등한 유형의 메시지)을 클릭했다는 메시지를 받고 button1_Click
위 의 메소드를 호출했습니다 . 이 메소드가 리턴 될 때까지이 루프는 대기 상태에 있습니다. 이 과정에는 2 초가 걸리며이 동안에는 메시지가 처리되지 않습니다.
창을 다루는 대부분의 작업은 메시지를 사용하여 수행됩니다. 즉, 메시지 루프가 메시지 펌핑을 중지하더라도 1 초 동안이라도 사용자가 빠르게 알아볼 수 있습니다. 예를 들어, 메모장이나 다른 프로그램을 자신의 프로그램 위로 옮긴 다음 다시 멀리 떨어 뜨리면 페인트 표시 메시지가 프로그램에 전송되어 창의 어느 영역이 갑자기 다시 표시되는지를 나타냅니다. 이러한 메시지를 처리하는 메시지 루프가 무언가를 기다리는 중이거나 차단 된 경우 페인팅이 수행되지 않습니다.
따라서 첫 번째 예에서 async/await
새 스레드를 만들지 않으면 어떻게됩니까?
글쎄, 당신의 방법은 두 가지로 나뉩니다. 이것은 광범위한 주제 유형 중 하나이므로 너무 자세하게 설명하지는 않지만 방법이 다음 두 가지로 나뉘어 있다고 말할 수 있습니다.
- 에
await
대한 호출을 포함하여로 이어지는 모든 코드GetSomethingAsync
- 다음의 모든 코드
await
삽화:
code... code... code... await X(); ... code... code... code...
재정렬 :
code... code... code... var x = X(); await X; code... code... code...
^ ^ ^ ^
+---- portion 1 -------------------+ +---- portion 2 ------+
기본적으로 메소드는 다음과 같이 실행됩니다.
- 그것은 모든 것을 실행합니다
await
그것은 GetSomethingAsync
그 일을 하는 메소드를 호출 하고 미래에 2 초가 완료되는 것을 반환합니다.
지금까지 우리는 여전히 메시지 루프에서 호출되는 메인 스레드에서 발생하는 button1_Click에 대한 원래 호출 내부에 있습니다. 코드 await
가 많은 시간이 걸리더라도 UI는 여전히 멈 춥니 다. 이 예에서는 그리 많지 않습니다
어떤 await
키워드가 함께 일부 영리한 컴파일러 마법, 일은 그것이 기본적으로 같은 "좋아, 당신은 단순히 여기에 버튼 클릭 이벤트 핸들러에서 돌아 갈거야 알고. 때 건에서와 같이 (우리 '입니다 다시 기다리고) 완료하기 위해, 아직 실행 코드가 남아 있기 때문에 알려주세요. "
실제로 SynchronizationContext 클래스 에 완료되었음을 알립니다. 현재 실행중인 실제 동기화 컨텍스트에 따라 실행 대기 상태가됩니다. Windows Forms 프로그램에서 사용되는 컨텍스트 클래스는 메시지 루프가 펌핑하는 큐를 사용하여 큐에 넣습니다.
따라서 메시지 루프로 돌아갑니다. 이제 창 이동, 크기 조정 또는 다른 버튼 클릭과 같은 메시지를 계속 펌핑 할 수 있습니다.
사용자에게는 이제 UI가 다시 반응하여 다른 버튼 클릭을 처리하고 크기를 조정하고 가장 중요하게 다시 그리기 때문에 멈추는 것처럼 보이지 않습니다.
- 2 초 후, 우리가 기다리고있는 것은 이제 완료됩니다. 이제 동기화 컨텍스트는 메시지 루프가보고있는 큐에 메시지를 배치하여 "이봐, 코드가 더 있습니다." "실행해야합니다."이 코드는 대기 후의 모든 코드입니다 .
- 메시지 루프가 해당 메시지에 도달하면 기본적으로 해당 메소드를 중단 한 직후에 "다시 입력"
await
하고 나머지 메소드 실행을 계속합니다. 이 코드는 메시지 루프에서 다시 호출되므로이 코드를 async/await
올바르게 사용 하지 않고 긴 작업을 수행 하면 메시지 루프가 다시 차단됩니다.
여기 후드 아래에 움직이는 부분이 많으므로 여기에 자세한 정보에 대한 링크가 있습니다. "필요한 것"이라고 말하려고했지만이 주제 는 매우 광범위하며 이러한 움직이는 부분 중 일부 를 아는 것이 매우 중요합니다 . async / await는 여전히 누설 개념이라는 것을 이해하게 될 것입니다. 근본적인 제한 사항과 문제 중 일부는 여전히 주변 코드로 유출되며 그렇지 않은 경우 일반적으로 아무 이유없이 무작위로 중단되는 응용 프로그램을 디버깅해야합니다.
그렇다면 GetSomethingAsync
2 초 안에 완료 될 실을 회전 시키면 어떻게 될까요? 예, 분명히 새로운 스레드가 있습니다. 그러나이 스레드 는이 메소드의 비동기 성 때문 이 아니라이 메소드의 프로그래머가 비동기 코드를 구현할 스레드를 선택했기 때문입니다. 거의 모든 비동기 I / O 는 스레드를 사용 하지 않고 다른 것을 사용합니다. async/await
자체적으로 새로운 스레드를 만들지는 않지만 분명히 "우리가 기다리는 것"은 스레드를 사용하여 구현 될 수 있습니다.
.NET에는 스레드를 자체적으로 가동시킬 필요는 없지만 여전히 비동기적인 많은 것들이 있습니다.
- 웹 요청 (및 시간이 걸리는 다른 많은 네트워크 관련 사항)
- 비동기 파일 읽기 및 쓰기
- 문제의 클래스 / 인터페이스라는 이름의 한 방법 경우 많은 더 좋은 기호는
SomethingSomethingAsync
나 BeginSomething
하고 EndSomething
하고 거기에 IAsyncResult
참여가.
일반적으로 이러한 것들은 후드 아래에서 실을 사용하지 않습니다.
자, "광범위한 주제"를 원하십니까?
버튼 클릭에 대해 Roslyn을 물어 보십시오 .
Roslyn을보십시오
나는 여기에 완전히 생성 된 클래스를 연결하지는 않지만 꽤 까다 롭습니다.