해당 게시글은 Concurrency in C# Cookbook을 기반,
Microsoft c# 문서를 기반으로 작성되었습니다.
동시성 프로그래밍을 설명하면서, 동기와 비동기의 차이를 아는 것은 중요하다.
따라서 비동기 프로그래밍에 대해서 소개하겠다.
비동기 프로그래밍
비동기 프로그래밍에는 크게 두 가지 이점이 있다.
첫 번째로 최종 사용자용 GUI 프로그램은 비동기 프로그래밍을 통해 응답성을 확보할 수 있다.
비동기 프로그램이라면 작업 중에도 사용자 입력에 반응할 수 있다.
두 번째로 서버 프로그램은 비동기 프로그래밍을 통해 규모를 변경할 수 있다.
서버 애플리케이션은 스레드 풀만 사용해도 어느 정도 규모를 변경할 수 있지만,
비동기 서버 애플리케이션은 대개 훨씬 큰 단위로 규모를 변경할 수 있다.
비동기 프로그래밍의 두 가지 이점은
모두 비동기 프로그래밍이 스레드를 가로막지 않고 자유롭게 풀어 준다는 특징을 바탕으로 한다.
즉, 비동기 프로그래밍의 기본은 스레드의 자유성이 보장된다는 것을 기반으로 하는 것이다.
GUI 프로그램에서 비동기 프로그래밍은 UI 스레드를 자유롭게 풀어준다.
// 동기 방식(나쁜 예)
button.Click += (s, e) => {
DownloadBigFile(); // 파일 다운로드 중에 UI 멈춤!
MessageBox.Show("다운로드 완료!");
};
// 비동기 방식(좋은 예)
button.Click += async (s, e) => {
await DownloadBigFileAsync(); // 비동기로 실행, UI 스레드는 자유로움!
MessageBox.Show("다운로드 완료!");
};
코드와 단순 "비동기 프로그래밍은 UI 스레드를 자유롭게 풀어준다" 라는 말로는
사실 이해하기 어렵다.
" 비동기 프로그래밍에서의 UI 스레드를 자유롭게 풀어준다는 뜻이란, "
C#의 비동기 모델 (TAP - Task-based Asynchronous Pattern)인
async/awit와 Tash 또는 Task<T> 기반의 언어 수준을 통해
UI 스레드를 멈추지 않고 처리할 수 있는 구조를 제공한다는 것이다.
await는 작업 완료 전까지 메서드를 잠시 중단하고, UI 스레드로 즉시 제어권을 반환한다.
이를 통해 UI 스레드가 다운로드 및 DB 작업 등 무거운 처리에 묶이지 않고 사용자 입력을 계속 처리하는 구조가 된다.
여기서.
"UI 스레드가 무거운 처리에 묶이지 않고 사용자 입력을 계속 처리하는 구조"
=> UI 스레드가 자유로워진다는 뜻이다.
"UI 반응성 유지 공식 권장 방식"
이에 대해 조금더 깊이 설명해보자면,
UI 반응성 유지 공식 권장 방식에 대해서 언급해보겠다.
Windows (UWP, WinForms, WPF ... ) 공식 문서 상에서도,
- UI 스레드에서 실행 가능한 시간은 짧게 유지하고
- 장시간 처리 로직은 비동기 API 호출 또는 Task.Run 등으로 백그라운드로 오프 로드하라고 권장한다.
WPF 역시 Dispatcher.InvokeAsync 등을 통해 UI 스레드 접근을 관리하며,
작업은 비동기로 실행하도록 가이드한다.
즉, 오래 걸리는 작업을 UI 바깥에서 처리하고, Dispatcher 통해 UI 업데이트하는 것이다.
private async void NextMove_Click(object sender, RoutedEventArgs e)
{
// UI 스레드는 await 지점에서 즉시 반환되어 사용자 입력을 받는 상태 유지
await System.Threading.Tasks.Task.Run(() => ComputeNextMove());
// 백그라운드 작업 완료 후 UI 업데이트
}
즉 다시 돌아와
"UI 스레드를 자유롭게 풀어준다"는 의미는
await 같은 동시성 프로그래밍 기반 원리를 사용하여 UI 스레드를 즉시 반환하여
사용자는 앱이 '멈춘 듯한' 느낌을 받지 않게 하고,
작업이 끝나면 결과만 UI에 반영하여 "UI 스레드를 자유롭게 풀어준다" 라는 의미가 된다.
즉 한 줄 요약하자면
UI가 멈추지 않고 계속 반응할 수 있게 해준다는 의미이다.
최신 비동기 닷넷 애플리케이션은 async와 await, 두 가지 키워드를 사용한다.
메서드 선언에 추가하는 async 키워드는 두 가지 목적을 지닌다.
async 키워드의 두 가지 목적
- 메서드 안에서 await 키워드를 사용할 수 있게 하고,
- 컴파일러에 해당 메서드의 상태 머신을 생성하라고 지시한다.
작업 방식은 yield가 작업을 반환하는 방식과 비슷하다.
작업 절차는 다음과 같다.
- async 메서드는 값을 반환해야 할 때는 Task<TResult>를 반환하고,
- 값을 반환하지 않을 떄는 Task 또는 ValueTask 같은 '유사 Task' 형식을 반환한다.
그럼 말을 잠깐 정돈해보자.
일단 async키워드의 두 가지 목적에서
컴파일러에 해당 메서드의 상태 머신을 생성하라고 지시한다는 듯은
컴파일러가 async 메서드를 "상태 머신"으로 변환한다는 뜻이다.
Review underlying concepts
When you implement asynchronous programming in your C# code, the compiler transforms your program into a state machine. This construct tracks various operations and state in your code, such as yielding execution when the code reaches an await expression, and resuming execution when a background job completes.
(Microsoft 출저)
Keep the UI thread responsive - UWP applications
Users expect an app to remain responsive while it does computation, regardless of the type of machine.
learn.microsoft.com
https://learn.microsoft.com/en-us/answers/questions/1366732/ui-freezing-due-to-task-run-activity-in-async-awai?utm_source=chatgpt.com
https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-scenarios?utm_source=chatgpt.com
Asynchronous programming scenarios - C#
Learn about the C# language-level asynchronous programming model provided by .NET Core and explore example code for I/O-bound and CPU-bound scenarios.
learn.microsoft.com
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await
'프로그래밍 언어 > C#' 카테고리의 다른 글
동시성의 개요 (2) | 2025.06.17 |
---|---|
박싱 언박싱 (0) | 2025.05.17 |
.NET 과 C#의 아키텍처 (4) | 2025.05.17 |
IEnumerator<T> 인터페이스 (0) | 2025.05.16 |
C# out 키워드 (1) | 2024.07.27 |