Main 메서드와 STAThread 속성
C#에서 비동기 메서드를 동기적으로 호출하는 구조를 포함하고 있습니다. 주로 Task.Run과 await 키워드를 사용하여 비동기 메서드를 처리하는 방식입니다. 이 코드를 더 잘 이해하기 위해 각 부분을 세분화해서 설명드리겠습니다.
1. Main 메서드와 STAThread 속성
- Main 메서드는 C# 애플리케이션의 진입점(entry point) 입니다.
- STAThread 속성은 Windows Forms 또는 WPF 애플리케이션에서 메인 스레드가 단일 스레드 아파트(Single-Threaded Apartment, STA) 모드로 실행되도록 지정합니다. 이는 주로 COM 상호 운용성(Interoperability)과 관련이 있습니다. Windows Forms 및 WPF에서 UI 스레드는 STA 모드로 실행되어야 합니다.
// FetchComplexDetailsClass:주로 크롤링작업이 이루어지는 프로그램작업일떄에 쓰이는 호출방법
// FetchComplexDetailsClass:주로 크롤링작업이 이루어지는 프로그램작업일떄에 쓰이는 호출방법
// FetchComplexDetailsClass:주로 크롤링작업이 이루어지는 프로그램작업일떄에 쓰이는 호출방법
[STAThread]
static void Main()
{
// 비동기 메서드를 호출하는 부분
Task.Run(async () =>
{
FetchComplexDetailsClass frm = new FetchComplexDetailsClass();
await frm.RUN();
}).GetAwaiter().GetResult(); // 비동기 작업이 완료될 때까지 대기
}
2. Task.Run(async () => { ... })
- Task.Run은 주어진 델리게이트 또는 메서드를 비동기적으로 실행하기 위해 새로운 태스크를 생성합니다.
- async () => { ... }는 비동기 메서드를 정의하는 람다 표현식입니다. 이 람다 안에서 비동기 작업을 수행할 수 있습니다.
- 이 부분은 백그라운드 스레드에서 비동기 작업을 수행하게 합니다. 이 경우 frm.RUN() 메서드를 비동기적으로 호출하려고 합니다.
3. await frm.RUN()
- await는 비동기 메서드를 기다리게 하며, 메서드가 완료될 때까지 나머지 코드를 실행하지 않습니다.
- frm.RUN()은 FetchComplexDetailsClass 객체의 RUN이라는 비동기 메서드를 호출합니다.
- 이 메서드가 완료될 때까지 현재 작업(스레드)이 대기 상태에 들어갑니다. RUN 메서드 내부에서 비동기 작업(예: 파일 I/O, 네트워크 호출 등)을 처리하고 그 결과를 반환할 때까지 기다리게 됩니다.
4. .GetAwaiter().GetResult()
- .GetAwaiter().GetResult()는 비동기 작업이 완료될 때까지 기다리면서, 비동기 결과를 동기적으로 처리하는 방법입니다.
- GetAwaiter()는 Task에서 비동기 작업의 상태를 가져옵니다.
- GetResult()는 비동기 작업이 완료될 때까지 기다리고, 그 결과를 동기적으로 반환합니다. 이 부분에서 예외가 발생하면 AggregateException을 발생시킬 수 있습니다.
5. 전체 흐름 설명
- Main 메서드 실행: 프로그램이 시작되면 Main 메서드가 호출됩니다. 여기서는 STAThread 속성 덕분에 단일 스레드 아파트에서 실행됩니다.
- Task.Run 실행: Task.Run은 새로운 비동기 작업을 시작합니다. 이 작업은 백그라운드 스레드에서 실행됩니다. async 람다 표현식 안에서 비동기 작업을 호출하고 있습니다.
- await frm.RUN(): frm.RUN() 비동기 메서드를 호출하면서, 이 메서드가 완료될 때까지 기다립니다. 이 메서드 내부에서 실제 비동기 작업이 수행됩니다(예를 들어, 네트워크 요청 또는 데이터 처리).
- GetAwaiter().GetResult(): await가 내부적으로 비동기 작업을 기다리지만, .GetAwaiter().GetResult()를 통해 해당 작업이 완료될 때까지 현재 스레드를 동기적으로 차단합니다. 즉, 이 코드가 없으면 비동기 메서드의 작업이 완료되기 전에 Main이 종료되었을 수 있기 때문에, 프로그램이 예기치 않게 종료되지 않도록 합니다.
- 비동기 메서드 완료 후 종료: frm.RUN() 메서드가 완료되면, Task.Run 내의 비동기 작업이 종료되고, Main 메서드가 종료됩니다. 이제 프로그램이 정상적으로 종료됩니다.
동기와 비동기 결합
- 비동기 작업은 일반적으로 UI 스레드를 차단하지 않으며, 다른 작업을 처리하는 동안 동시에 실행됩니다.
- 하지만 GetAwaiter().GetResult()는 비동기 작업을 동기적으로 기다리게 하므로, Main 스레드는 비동기 작업이 완료될 때까지 대기하고, 작업이 완료된 후에 종료됩니다.
6. 왜 이런 방식으로 사용하나요?
- 비동기 작업을 UI 스레드에서 처리할 때 동기적으로 메인 스레드가 대기하도록 강제하는 경우가 있습니다. 이를 통해 UI를 잠시 멈추게 하지 않고 비동기 작업을 안전하게 처리할 수 있습니다.
- Task.Run을 사용하면 비동기 작업이 백그라운드에서 실행되므로 UI 스레드의 블로킹을 피할 수 있습니다. 다만, .GetAwaiter().GetResult()를 사용하여 그 결과를 동기적으로 기다리는 방식은 메인 스레드가 작업 완료를 기다리게 만들기 때문에 주로 Main 메서드에서 비동기 작업을 호출할 때 사용됩니다.
결론
- Task.Run을 통해 비동기 작업을 백그라운드에서 시작하고, await를 사용해 비동기 메서드를 기다립니다.
- GetAwaiter().GetResult()를 사용하여 비동기 작업이 완료될 때까지 메인 스레드를 동기적으로 대기하게 만듭니다.
- 이 방식은 주로 콘솔 애플리케이션에서 비동기 작업을 동기적으로 처리하고 싶을 때 사용됩니다.
'c# 언어 > 고급과정' 카테고리의 다른 글
C#에서 비동기 작업을 별도의 스레드에서 실행 (0) | 2025.01.02 |
---|---|
WindowsBase.dll/PresentationFramework.DLL/PresentationCore.DLL (0) | 2023.04.30 |