나는 새로운 비동기에 대해 읽었습니다.await
키워드를 사용하고 멋지게 들리지만, 지금까지 본 인트로 비디오 중 하나에 대한 답을 찾을 수 없었던 핵심 질문이 하나 있습니다 (필자도 백서를 읽어보십시오).
전화가 있다고 가정 해 봅시다.await
기본 UI 스레드에서 중첩 된 함수에서. 이 시점에서 스레드는 어떻게됩니까? 제어가 메시지 루프로 돌아가고 UI 스레드가 다른 입력을 처리 할 수 있습니까?
대기중인 작업이 완료되면 전체 스택이 메시지 대기열로 밀어 넣어 져서 해당 중첩 함수를 통해 제어가 반환되거나 여기서 완전히 발생하는 것입니까?
그리고 두 번째로 (내가주의를 기울이는 동안) 비동기 메소드를 왜 라벨링해야하는지 이해하지 못한다.async
. 어떤 메서드를 비동기 적으로 실행할 수 있습니까? 메서드를 비동기 적으로 실행하려고하지만 비동기 키워드가없는 경우에는 어떻게해야합니까? 단순히이를 수행 할 수있는 방법이 있습니까?
건배. :)
편집하다:필자가 샘플 코드를 컴파일 할 수 있다면, 아마 나 자신을 알아낼 수있을 것이다. 그러나 한 가지 이유 또는 다른 이유로 나는 블록을 실행 중이다. 내가 정말로 알고 싶은 것은 지속이 어느 정도 지속 되는가하는 것입니다 ... 전체 호출 스택을 고정 시키거나, 작업이 완료 될 때 다시 시작하거나, 아니면 지금까지만 돌아갈 수 있습니까? 연속을 지원하기 위해 함수 자체를 비동기로 표시해야합니까, 아니면 원래 요청했듯이 전체 호출 스택을 계속 수행합니까?
그 경우하지 않는다비동기 호출 함수가 비동기 호출을 기다리는 경우 어떻게됩니까? 거기 블록합니까? 기다리고있는 시점을 패배시키지 않겠습니까? 나는 당신이 내가 누군가를 채울 수 있기를 바란다는 것을 여기서 이해하지 못한다는 것을 알기를 바랍니다. 그래서 나는 이것을 계속 배울 수 있습니다.
기본 UI 스레드에서 중첩 된 함수를 기다리는 호출이 있다고 가정합니다. 이 시점에서 스레드는 어떻게됩니까? 제어가 메시지 루프로 돌아가고 UI 스레드가 다른 입력을 처리 할 수 있습니까?
예. 때를await
기다릴만한 (예 :Task<TResult>
), 스레드 내의 현재 스레드 위치async
메소드가 캡처됩니다. 그런 다음 대기 상태가 완료 될 때 실행될 메소드의 나머지 ( "계속")를 대기열에 넣습니다 (예 :Task<TResult>
완료).
그러나, 수행 할 수있는 최적화가 있습니다 : 대기가 이미 완료된 경우await
기다릴 필요가 없으며 메서드를 즉시 계속 실행합니다. 이를 "빠른 경로"라고합니다.여기에 설명되어있다..
대기중인 작업이 완료되면 전체 스택이 메시지 대기열로 밀어 넣어 져서 해당 중첩 함수를 통해 제어가 반환되거나 여기서 완전히 발생하는 것입니까?
스레드의 현재 위치가 UI 메시지 큐에 푸시됩니다. 세부 사항은 조금 더 복잡합니다.TaskScheduler.FromCurrentSynchronizationContext
~ 않는 한SynchronizationContext.Current
~이다.null
, 그 경우에 그들은 예정되어있다.TaskScheduler.Current
. 또한이 동작을 호출하여 재정의 할 수 있습니다.ConfigureAwait(false)
이는 항상 스레드 풀에서 연속을 예약합니다. 이후SynchronizationContext.Current
UISynchronizationContext
WPF / WinForms / Silverlight의 경우이 연속체가 UI 메시지 큐에 푸시됩니다.
그리고 두 번째로 (내가주의를 끄는 동안) 비동기 메서드를 비동기로 레이블링해야하는 이유를 실제로 이해하지 못합니다. 어떤 메서드를 비동기 적으로 실행할 수 있습니까? 메서드를 비동기 적으로 실행하려고하지만 비동기 키워드가없는 경우에는 어떻게해야합니까? 단순히이를 수행 할 수있는 방법이 있습니까?
이들은 "비동기"라는 단어와 약간 다른 의미입니다. 그만큼async
키워드를 사용하면await
예어. 다른 말로,async
메소드는await
. 구식 비동기 대리자 (예 :BeginInvoke
/EndInvoke
)는async
. 비동기 대리자는ThreadPool
실,하지만async
메서드는 UI 스레드에서 실행됩니다 (UI 컨텍스트에서 호출되고 호출하지 않는다고 가정).ConfigureAwait(false)
).
당신이 (비 -async
) 메소드는ThreadPool
스레드, 당신은 이렇게 할 수 있습니다 :
await Task.Run(() => MyMethod(..));
내가 정말로 알고 싶은 것은 지속이 어느 정도 지속 되는가하는 것입니다 ... 전체 호출 스택을 고정 시키거나, 작업이 완료 될 때 다시 시작하거나, 아니면 지금까지만 돌아갈 수 있습니까? 연속을 지원하기 위해 함수 자체를 비동기로 표시해야합니까, 아니면 원래 요청했듯이 전체 호출 스택을 계속 수행합니까?
현재 위치가 캡처되고 연속 실행시 "다시 시작"됩니다. 사용하는 모든 함수await
계속을 표시하려면 반드시 표시해야합니다.async
.
전화하면async
방법은 비 -async
방법을 사용하면Task
개체를 직접. 이것은 정상적으로 수행되지 않습니다. 최상위async
메서드가 반환 할 수 있습니다.void
, 그렇게하지 않을 이유가 없습니다.async
이벤트 핸들러.
유의 사항async
순전히 컴파일러 변환입니다. 즉,async
메서드는 컴파일 된 후 일반 메서드와 정확하게 같습니다. .NET 런타임은 특별한 방법으로 그들을 처리하지 않습니다.
Task
, 그래서 당신은 할 필요가있다.await
그것은 예외를 볼 수 있습니다. 그런 다음 호출 스택 위로 이동합니다. - Stephen ClearyTask
개체, 나중에 관찰 할 수 있습니다. 전체 스택이 캡처 된 경우에도 (이 경우에는 그렇지 않습니다.)catch
예외가 실행되기 때문에 블록을 실행할 수 없습니다.Task
. - Stephen Cleary
그것은 Awaitable의 행동에 달려 있습니다.
동기 실행 옵션이 있습니다. 즉, 스레드에서 실행되고 동일한 스레드에서 대기 상태로 제어를 되돌립니다.
비동기 적으로 실행되도록 선택하면 기다리는 시간이 콜백을 예약하는 스레드에서 대기자가 다시 호출됩니다. 그 동안 호출 스레드는 비동기 작업을 시작하고 대기 상태에 빠져 있기 때문에 대기 상태가 해제되고 대기 상태는 계속 대기 상태의 콜백에 연결되어 있기 때문에 해제됩니다.
두 번째 질문에서 async 키워드는 메서드가 비동기 적으로 호출되는지 아닌지에 대한 것이 아니라 해당 메서드의 본문이 비동기 코드 인라인 자체를 호출하려고하는지 여부와 관련이 없습니다.
나는. Task 또는 Task를 반환하는 모든 메서드는 비동기 적으로 (기다리거나 계속 계속됨) 호출 할 수 있지만 async로 표시하면 해당 메서드는 본문에서 await 키워드를 사용할 수 있으며 반환 할 때 Task를 반환하지는 않지만 단순히 반환합니다. T는 전체 본문이 Task가 실행하는 상태 시스템으로 다시 작성되기 때문에.
방법이 있다고 가정 해 봅시다.
public async Task DoSomething() {
}
UI 스레드에서 호출하면 작업이 반환됩니다. 이 시점에서 다음을 사용하여 작업을 차단할 수 있습니다..Wait()
또는.Result
TaskScheduler에서 async 메서드를 실행하거나.RunSynchronously()
UI 스레드에서 실행됩니다. 물론 내부에서 일어나는 모든 일이 기다리고 있습니다.DoSomething
기본적으로 또 다른 연속체이므로 TaskScheduler 스레드에서 코드의 일부를 실행하게 될 수도 있습니다. 그러나 결국 UI 스레드는 정상적인 동기 메서드와 마찬가지로 완료 될 때까지 차단됩니다.
또는 다음을 사용하여 일정을 예약 할 수 있습니다..ContinueWith()
작업이 완료되면 TaskScheduler에 의해 호출되는 작업을 만듭니다. 이렇게하면 UI 스레드에서 수행중인 작업을 계속 수행하는 현재 코드로 컨트롤이 즉시 반환됩니다. 연속은 콜 스택을 캡처하지 않으며 단순히 액션 일 뿐이므로 외부 범위에서 액세스하는 모든 변수를 캡처합니다.