저는 프로젝트를 진행하면서 Thread 클래스를 활용하여 필요할 때마다 스레드를 생성하여 사용하였습니다.
하지만 C# 프로그래밍에서 이미 존재하는 ThreadPool에서 사용 가능한 작업 쓰레드를 할당받아 사용하는 것이 권장하는 방식임을 알게 되었습니다.
ThreadPool의 작업 쓰레드를 활용한 방식
- Task
- Task<T>
- BackgroundWorker
- ThreadPool 클래스
- 비동기 델리게이트(Async Delegate)
저는 WPF에서 async/await를 활용하는 간단한 코드를 작성하였습니다.
과연 Console.WriteLine() 부분은 어떤 순서대로 콘솔에 표시될까요?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
AsyncShowText();
Console.WriteLine("AsyncShowText() 다음 문장");
}
private async void AsyncShowText()
{
Task task = Task.Factory.StartNew(() => AsyncDelay3Test());
Console.WriteLine("AsyncDelay3Test() 다음 문장");
await task;
Console.WriteLine("await task 다음 실행");
txtBox.Text = "await task 다음 실행";
}
private async void AsyncDelay3Test()
{
//Thread.Sleep(3000);
await Task.Delay(3000);
Console.WriteLine("Async 3초뒤 실행");
try
{
txtBox.Text = "여기서 오류 발생";
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
프로그램의 구조를 간단하게 만들어 보았습니다.
메서드 별로 주석을 달아 설명을 진행하였습니다..
우선 async는 컴파일러에게 해당 메서드가 await를 가지고 있다고 알립니다.
await는 awaitable 객체가 완료되기를 기다리는 역할입니다.
await는 UI 스레드가 정지되지 않고 메시지 루프를 계속 돌 수 있도록 필요한 코드를 컴파일러가 자동으로 추가합니다.
그렇기 때문에 txtBox.Text에 Invoke, BeginInvoke 작업이 필요 없는 것입니다.
//버튼을 눌러 AsyncShowText()를 실행한다.
private void Btn_Click(object sender, RoutedEventArgs e)
{
AsyncShowText();
// AsyncShowText에서 반환되면서 다음 문장이 2번째로 출력됩니다.
Console.WriteLine("ShowText() 다음 문장");
}
//async
private async void AsyncShowText()
{
//task 객체가 생성되면서 AsyncDelay3Test()를 시작합니다.
//AsyncDelay3Test()가 호출될 때, await Task.Delay(3000)에서 바로 반환됩니다.
Task task = Task.Factory.StartNew(() => AsyncDelay3Test());
//await에서 반환되면서 1번째로 출력됩니다.
Console.WriteLine("AsyncDelay3Test() 다음 문장");
//await를 만나면서 Btn_Click으로 반환됩니다.
await task;
//Btn_Click의 콘솔 출력 완료 후 다음 동작을 진행합니다.
//AsyncShowText()는 UI 스레드에서 실행되기 때문에 Invoke, BeginInvoke가 필요없습니다.
Console.WriteLine("await task 다음 실행"); // --> 3번째로 출력됩니다.
txtBox.Text = "await task 다음 실행"; // --> TextBox에 내용이 출력됩니다.
}
private async void AsyncDelay3Test()
{
//await를 만나면서 AsyncShowText()으로 반환됩니다.
await Task.Delay(3000);
//3초가 지난 후 await 아래코드가 실행됩니다.
Console.WriteLine("Async 3초뒤 실행"); //-> 4번째로 출력이 됩니다.
try
{
//UI 스레드가 아닌 곳에서 컨트롤에 접근했기 때문에 오류가 발생합니다.
//오류를 해결하기 위해 Invoke, BeginInvoke 작업이 필요합니다.
txtBox.Text = "여기서 오류 발생";
}
catch(Exception ex)
{
//오류가 발생하므로 5번째에 에러 메시지가 출력된다.
Console.WriteLine(ex.Message);
}
}
📌 실행 결과
코드에 설명된 순서대로 콘솔에 출력이 됩니다.
'C#' 카테고리의 다른 글
[C#] - 레지스트리의 사용 (0) | 2023.01.04 |
---|---|
[C#] - 프로그램의 실행 과정 (1) | 2022.12.28 |