async 키워드
async 키워드 (C# reference)
async 한정자를 쓰면 메서드나 람다 식, 무명 메서드를 비동기로 만들 수 있어요. 이 한정자를 메서드나 식에 붙이면 그건 async 메서드가 되는 거죠. 아래 예시는 ExampleMethodAsync라는 async 메서드를 정의해요.
public async Task<int> ExampleMethodAsync()
{
//...
}
본문
비동기 프로그래밍이 처음이거나, async 메서드가 await 연산자로 어떻게 호출자의 스레드를 막지 않으면서 오래 걸리는 작업을 처리하는지 잘 모르겠다면, async 및 await를 사용한 비동기 프로그래밍의 소개를 먼저 읽어 보세요. 아래 코드는 async 메서드 안에서 xref:System.Net.Http.HttpClient.GetStringAsync%2a?displayProperty=nameWithType 메서드를 호출하는 모습이에요.
string contents = await httpClient.GetStringAsync(requestUrl);
async 메서드는 첫 번째 await 식에 도달할 때까지 동기적으로 실행돼요. 그 지점에서 메서드는 기다리던 작업이 끝날 때까지 일시 중지되고, 그동안 제어는 메서드의 호출자에게 돌아가요. 다음 절의 예시가 바로 이 흐름을 보여줘요.
async 키워드를 붙인 메서드 안에 await 식이나 문이 하나도 없다면, 그 메서드는 동기적으로 실행돼요. 컴파일러는 await 문을 포함하지 않는 async 메서드에 대해 경고를 띄우는데, 그런 상황이 오류를 암시할 수 있기 때문이에요. 자세한 내용은 컴파일러 경고(수준 1) CS4014를 참고하세요.
async 키워드는 문맥 키워드예요. 메서드나 람다 식, 무명 메서드를 수식할 때만 키워드로 취급되고, 그 외의 모든 문맥에서는 컴파일러가 이를 식별자로 해석해요.
아래 예시는 async 이벤트 처리기인 StartButton_Click과 async 메서드 ExampleMethodAsync 사이의 구조와 제어 흐름을 보여줘요. async 메서드가 돌려주는 결과는 웹 페이지의 문자 수예요. 이 코드는 Visual Studio에서 만든 Windows Presentation Foundation(WPF) 앱이나 Windows Store 앱에서 동작하도록 맞춰져 있으니, 앱 구성에 관한 내용은 코드 주석을 참고하세요.
이 코드는 Visual Studio에서 WPF(WPF) 앱이나 Windows Store 앱으로 실행할 수 있어요. StartButton이라는 이름의 Button 컨트롤과 ResultsTextBox라는 이름의 Textbox 컨트롤이 필요하죠. 이름과 처리기를 아래처럼 설정해야 해요.
<Button Content="Button" HorizontalAlignment="Left" Margin="88,77,0,0" VerticalAlignment="Top" Width="75"
Click="StartButton_Click" Name="StartButton"/>
<TextBox HorizontalAlignment="Left" Height="137" Margin="88,140,0,0" TextWrapping="Wrap"
Text="<Enter a URL>" VerticalAlignment="Top" Width="310" Name="ResultsTextBox"/>
WPF 앱으로 실행하려면 이렇게 해요.
- MainWindow.xaml.cs의
MainWindow클래스에 이 코드를 붙여 넣어요. - System.Net.Http에 대한 참조를 추가해요.
- System.Net.Http에 대한
using지시문을 추가해요.
Windows Store 앱으로 실행하려면 이렇게 해요.
- MainPage.xaml.cs의
MainPage클래스에 이 코드를 붙여 넣어요. - System.Net.Http와 System.Threading.Tasks에 대한
using지시문을 추가해요.
:::code language="csharp" source="./snippets/async/wpf/MainWindow.xaml.cs" id="1":::
[!IMPORTANT] 작업과 작업을 기다리는 동안 실행되는 코드에 대해 더 알고 싶다면 async 및 await를 사용한 비동기 프로그래밍을 보세요. 비슷한 요소를 쓰는 전체 콘솔 예시는 작업이 완료되면 비동기 작업 처리(C#)에서 확인할 수 있어요.
반환 형식
async 메서드는 다음 반환 형식을 가질 수 있어요.
- xref:System.Threading.Tasks.Task
- xref:System.Threading.Tasks.Task`1
void. 일반적으로async void메서드는 이벤트 처리기가 아닌 코드에는 피하는 게 좋아요. 호출자가 해당 메서드를await할 수 없고, 성공적인 완료나 오류 조건을 알려줄 별도의 메커니즘을 직접 구현해야 하기 때문이죠.- 접근 가능한
GetAwaiter메서드를 가진 모든 형식.System.Threading.Tasks.ValueTask<TResult>형식이 그런 구현의 하나로, NuGet 패키지System.Threading.Tasks.Extensions를 추가하면 사용할 수 있어요.
async 메서드는 in, ref, ref readonly, out 매개 변수를 선언할 수 없고, 참조 반환 값도 가질 수 없어요. 다만 그런 매개 변수를 가진 메서드를 호출하는 건 가능해요.
메서드의 return 문이 TResult 형식의 피연산자를 지정한다면 async 메서드의 반환 형식으로 Task<TResult>를 지정해요. 메서드가 완료될 때 의미 있는 값을 돌려주지 않는다면 Task를 쓰면 돼요. 즉 메서드 호출은 Task를 반환하지만, Task가 완료되면 그 Task를 기다리는 await 식은 void로 평가되는 거죠. void 반환 형식은 주로 이벤트 처리기를 정의할 때 쓰는데, 이벤트 처리기는 그 반환 형식을 요구하기 때문이에요. void를 반환하는 async 메서드의 호출자는 그 메서드를 await할 수도, 메서드가 던지는 예외를 잡을 수도 없어요. 성능이 중요한 코드 구간에서 메모리 할당을 줄이려면 GetAwaiter 메서드를 가진 다른 형식, 보통 값 형식을 반환하는 게 좋아요.
더 자세한 내용과 예시는 Async 반환 형식을 참고하세요.