.NET 비동기 프로그래밍의 모범 사례

비동기 프로그래밍을 사용하면 애플리케이션의 메인 또는 실행 스레드를 차단하지 않고도 리소스 집약적 인 I / O 작업을 수행 할 수 있습니다. 유익하고 구현하기 쉬운 것처럼 보이지만 많은 복잡성과 위험이 따릅니다. 비동기 프로그래밍과 관련된 잠재적 위험, 특히 권장 사례를 따르지 않는 방식으로 비동기 프로그래밍을 잘못 사용하면 교착 상태, 프로세스 충돌 및 성능 저하가 있습니다. 또한 비동기 코드를 작성하고 디버깅하는 데 능숙해야합니다.

비동기 메서드에서 void 반환 유형을 사용하지 마십시오.

C #의 메서드는 메서드 서명에서 async 키워드를 사용하여 비동기 메서드로 만들어집니다. 비동기 메서드 내에 하나 이상의 await 키워드가있을 수 있습니다. await 키워드는 일시 중단 지점을 나타내는 데 사용됩니다. C #의 비동기 메서드에는 Task, Task 및 void와 같은 반환 형식 중 하나가있을 수 있습니다. "await"키워드는 비동기 메서드에서 메서드에 일시 중단 및 재개 지점이있을 수 있음을 컴파일러에 알리는 데 사용됩니다.

TPL을 사용할 때 TPL에서 void를 반환하는 것과 동일한 것은 비동기 작업입니다. async void는 비동기 이벤트에만 사용되어야한다는 것을 알고 있어야합니다. 다른 곳에서 사용하면 오류가 발생합니다. 즉, 반환 형식이 void 인 비동기 메서드는 권장되지 않습니다. void를 반환하는 비동기 메서드는 응용 프로그램에서 예외로 작업 할 때 다른 의미를 갖기 때문입니다.

반환 유형이 Task 또는 Task 인 비동기 메서드에서 예외가 발생하면 예외 개체가 Task 개체 내에 저장됩니다. 반대로 반환 유형이 void 인 비동기 메서드가있는 경우 연결된 Task 개체가 없습니다. 이러한 예외는 비동기 메서드가 호출 될 때 활성화 된 SynchronizationContext에서 발생합니다. 즉, 비동기 메서드 내부에 작성된 예외 처리기를 사용하여 비동기 void 메서드 내에서 발생한 예외를 처리 할 수 ​​없습니다. 반환 유형이 void 인 비동기 메서드도 오류 처리 의미 체계의 차이로 인해 테스트하기 어렵습니다. 참고로 System.Threading 네임 스페이스의 SynchronizationContext 클래스는 .Net의 동기화 컨텍스트를 나타내며 작업을 다른 컨텍스트에 큐에 넣는 데 도움이됩니다.

다음 코드 목록은이를 보여줍니다. Test 및 TestAsync라는 두 가지 메서드가 있으며 후자는 예외를 throw합니다.

public class AsyncDemo

   {

       public void Test()

       {

           try

           {

               TestAsync();

           }

           catch (Exception ex)

           {

               Console.WriteLine(ex.Message);

           }

       }

       private async void TestAsync()

       {

           throw new Exception("This is an error message");

       }

   }

다음은 AsyncDemo 클래스의 인스턴스를 만들고 Test 메서드를 호출하는 방법입니다.

static void Main(string[] args)

       {

           AsyncDemo obj = new AsyncDemo();

           obj.Test();

           Console.Read();

       }

테스트 메서드는 TestAsync 메서드를 호출하고 호출은 TestAsync 메서드 내부에서 throw 된 예외를 처리 할 목적으로 try-catch 블록 내부에 래핑됩니다. 그러나 TestAsync 메서드 내에서 throw 된 예외는 포착되지 않습니다. 즉, 호출자 메서드 Test 내에서 처리됩니다.

비동기 및 동기 코드 혼합 방지

동기 코드와 비동기 코드를 혼합해서는 안됩니다. Task.Wait 또는 Task.Result를 호출하여 비동기 코드를 차단하는 것은 나쁜 프로그래밍 습관입니다. 비동기 코드를 사용하는 것이 좋습니다. 이것이 오류가 발생하는 것을 방지하는 가장 안전한 방법입니다.

를 사용하여 교착 상태를 피할 수 있습니다. ConfigureAwait(continueOnCapturedContext: false)당신이 기다리는 전화를 할 때마다. 이것을 사용하지 않으면 await가 호출 된 지점에서 비동기 메서드가 차단됩니다. 이 경우 현재 컨텍스트를 캡처하지 않도록 대기자에게 알리는 것입니다. 사용하지 않을 특별한 이유가없는 한 .ConfigureAwait (false)를 사용하는 것이 좋습니다.

나는 미래의 블로그 게시물에서 비동기 프로그래밍에 대해 더 많이 논의 할 것입니다. 비동기 프로그래밍의 모범 사례에 대한 자세한 내용은 MSDN에서 Stephen Cleary의 훌륭한 기사를 참조하십시오.