your programing

C # 5 Async / Await-* 동시 *입니까?

lovepro 2020. 12. 25. 23:35
반응형

C # 5 Async / Await-* 동시 *입니까?


저는 C # 5의 새로운 비동기 관련 사항을 고려하고 있는데, 한 가지 특별한 질문이 나왔습니다.

나는 await키워드가 연속 전달 을 구현하는 깔끔한 컴파일러 트릭 / 구문 설탕 이라는 것을 이해합니다. 여기서 메서드의 나머지 부분은 Task개체 로 분할 되고 순서대로 실행되도록 대기하지만 제어는 호출 메서드로 반환됩니다.

내 문제는 현재 이것이 모두 단일 스레드에 있다고 들었습니다. 이것은이 비동기 작업이 실제로 연속 코드를 Task객체 로 변환 한 다음 Application.DoEvents()각 작업이 완료된 후 다음 작업을 시작하기 전에 호출 하는 방법 일 뿐이라는 것을 의미합니까 ?

아니면 내가 뭔가를 놓치고 있습니까? (질문의이 부분은 수사적입니다-나는 내가 뭔가를 놓치고 있다는 것을 완전히 알고 있습니다 :))


그것은이다 동시에 많은 뛰어난 asychronous 작업은 언제든지 진행이 될 수 있다는 의미에서. 다중 스레드 일 수도 있고 아닐 수도 있습니다 .

기본적으로 await는 계속을 "현재 실행 컨텍스트"로 다시 예약합니다. "현재 실행 콘텍스트"로 정의 SynchronizationContext.Current가 비없는 경우 null, 또는 TaskScheduler.Current더있을 경우 SynchronizationContext.

매개 변수 호출 ConfigureAwait하고 전달 하여이 기본 동작을 재정의 할 수 있습니다 . 이 경우 연속은 해당 실행 컨텍스트로 다시 예약되지 않습니다. 이것은 일반적으로 스레드 풀 스레드에서 실행된다는 것을 의미합니다.falsecontinueOnCapturedContext

라이브러리 코드를 작성하지 않는 한 기본 동작은 정확히 원하는 것입니다. WinForms, WPF 및 Silverlight (즉, 모든 UI 프레임 워크)는를 제공 SynchronizationContext하므로 연속이 UI 스레드에서 실행되고 UI 개체에 안전하게 액세스 할 수 있습니다. ASP.NET은 또한 SynchronizationContext올바른 요청 컨텍스트에서 연속이 실행되도록하는를 제공합니다.

다른 스레드 (스레드 풀 스레드 Thread, 및 포함 BackgroundWorker)는 SynchronizationContext. 따라서 기본적으로 콘솔 앱 및 Win32 서비스에는 전혀 없습니다 SynchronizationContext. 이 상황에서 연속은 스레드 풀 스레드에서 실행됩니다. 사용하여 콘솔 응용 프로그램 데모 이유입니다 await/ async호출을 포함 Console.ReadLine/ ReadKey또는 차단 할 WaitA의를 Task.

.이 필요하다면 Nito.AsyncEx 라이브러리 에서 SynchronizationContext사용할 수 있습니다 . 그것은 기본적으로 그냥 제공 A를 호환 "메인 루프"를 . 콘솔 앱 및 단위 테스트에 유용하다고 생각합니다 (VS2012에는 이제 단위 테스트에 대한 기본 지원이 있음 ).AsyncContextasyncSynchronizationContextasync Task

에 대한 자세한 내용은 SynchronizationContext참조 내 2월 MSDN 문서를 .

아무 DoEvents때나 또는 이와 동등한 호출 이 없습니다 . 오히려 제어 흐름 이 끝까지 반환 되고 계속 (나머지 함수)이 나중에 실행되도록 예약됩니다. 이것은 DoEvents사용 했을 때와 같은 재진입 문제를 일으키지 않기 때문에 훨씬 더 깨끗한 솔루션 입니다.


async / await의 전체 아이디어는 연속 전달을 훌륭하게 수행하고 작업에 새 스레드를 할당하지 않는다는 것입니다. 새 스레드에서 연속 발생할 있으며 동일한 스레드에서 계속 될 수 있습니다 .


async / await의 실제 "고기"(비동기) 부분은 일반적으로 개별적으로 수행되며 호출자와의 통신은 TaskCompletionSource를 통해 수행됩니다. 여기에 쓰여진대로 http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

TaskCompletionSource 유형은 이름으로 언급되는 두 가지 관련 목적을 제공합니다. 두 가지 목적은 작업을 생성하기위한 소스이고 해당 작업을 완료하기위한 소스입니다. 본질적으로 TaskCompletionSource는 Task 및 완료에 대한 생산자 역할을합니다.

예는 매우 명확합니다.

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

를 통해 기다릴 수 TaskCompletionSource있는 Task개체에 액세스 할 수 있지만 다중 스레딩을 만든 async / await 키워드를 통하지는 않습니다.

많은 "느린"함수가 async / await 구문으로 변환 될 때 많이 사용할 필요가 없습니다 TaskCompletionSource. 그들은 그것을 내부적으로 사용할 것입니다 (그러나 결국 어딘가에 TaskCompletionSource비동기 결과를 가져야합니다)


내가 설명하고 싶은 방식은 "await"키워드가 단순히 작업이 완료 될 때까지 기다리지 만 기다리는 동안 호출 스레드에 실행을 양보한다는 것입니다. 그런 다음 Task의 결과를 반환하고 Task가 완료되면 "await"키워드 뒤의 문에서 계속됩니다.

내가 알아 차린 일부 사람들은 Task가 호출 스레드와 동일한 스레드에서 실행된다고 생각하는 것 같습니다. 이것은 올바르지 않으며 호출을 기다리는 메서드 내에서 Windows.Forms GUI 요소를 변경하여 증명할 수 있습니다. 그러나 가능한 경우 호출 스레드에서 연속이 실행됩니다.

Task가 완료 될 때 콜백 델리게이트 나 이벤트 핸들러가 필요하지 않은 깔끔한 방법입니다.

참조 URL : https://stackoverflow.com/questions/7663101/c-sharp-5-async-await-is-it-concurrent

반응형