회사에서 프로젝트를 진행하면서 계속해서 사용하는 것이 비동기 작업입니다.
코드로 비동기 작업을 구현하다 보면 꼬이는 경우가 간혹 발생하는데요
저는 이 문제를 해결하기 위해 많은 부분에 CancellationToken을 사용하여 해결합니다.
이번 포스팅은 CancellationToken에 대해 정리해보려 합니다.
| CancellationToken 이해
- Cancellationtoken은 .NET에서 비동기 작업을 관리하는 데 사용되는 중요한 요소 중 하나입니다.
Cancellationtoken를
작업이 취소되었을 때 작업을 정리하며 리소스를 해제하여 프로그램 관리에 더 도움을 주게 되며
주로 병렬 프로그래밍이나 비동기 프로그래밍에서 많이 사용합니다.
| CancellationToken의 주요 개념
1. CancellationTokenSource : CancellationToken을 생성하고 관리하는 데 사용
CancellationTokenSource을 사용하여 CancellationToken 객체를 생성하고 해당 토큰을 다른 비동기 작업에 전달
취소를 요청하려면 CancellationTokenSource의 Cancel 메서드 호출
예시)
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;
2. CancellationToken : 실제 취소 토큰, 비동기 작업 내에서 사용하여 작업을 취소하거나 취소 상태 확인
예시) IsCancellationRequested 속성을 사용한 작업 취소 상태 확인
if (cancellationToken.IsCancellationRequested)
{
// 작업을 중단하거나 정리합니다.
}
| CancellationToken의 기능
1. 비동기 작업 취소 : 실행 중인 작업을 취소하거나 중지
장기 실행 작업이나 무한 루프를 안전하게 중단하는 데 사용
2. 취소 토큰 전달 : 비동기 작업에 취소 토큰을 전달하는 데 사용,
작업이 실행 중에 토큰이 취소되면 해당 작업은 중단되거나 취소
3. 취소 토큰 결합 : 여러 작업을 조정하고 모니터링하기 위해 여러 취소 토큰을 결합
모든 관련 작업이 취소되면 기본 작업도 중지될 수 있음
CancellationToken의 기능들을 코드 예시와 함께 알아보겠습니다.
| CancellationToken 기능의 코드 예시
예시 1) 비동기 작업 취소 : 단일 작업 취소
class Program
{
static async Task Main()
{
// CancellationTokenSource를 생성하여 CancellationToken을 생성합니다.
var cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;
// 비동기 작업 시작
var task = Task.Run(() =>
{
while (!cancellationToken.IsCancellationRequested)
{
// 작업 수행 중...
Console.WriteLine("Working...");
Thread.Sleep(1000);
}
}, cancellationToken);
// 몇 초 후 작업을 취소
await Task.Delay(5000);
cancellationTokenSource.Cancel(); // 작업 취소 요청
try
{
await task; // 작업이 취소될 때 OperationCanceledException 예외 발생
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was canceled.");
}
}
}
예시 2) 비동기 작업 취소 : 여러 작업의 동시 취소
class Program
{
static async Task Main()
{
// CancellationTokenSource를 생성하여 CancellationToken을 생성합니다.
var cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;
// 여러 작업을 저장할 리스트를 생성합니다.
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(Task.Run(() =>
{
while (!cancellationToken.IsCancellationRequested)
{
// 작업 수행 중...
Console.WriteLine($"Working on Task {i}...");
Thread.Sleep(1000);
}
}, cancellationToken));
}
// 몇 초 후 모든 작업을 취소
await Task.Delay(5000);
cancellationTokenSource.Cancel(); // 작업 취소 요청
try
{
// 모든 작업이 취소될 때까지 대기
await Task.WhenAll(tasks.ToArray());
// 여러 작업이 취소될 때 OperationCanceledException 예외 발생
}
catch (OperationCanceledException)
{
Console.WriteLine("All tasks were canceled.");
}
}
}
예시 3) 비동기 작업 취소 : CancellationToken 결합
class Program
{
static async Task Main()
{
// 첫 번째 CancellationTokenSource를 생성하고 특정 시간(여기서는 2초) 이후에 취소될 토큰을 만듭니다.
var token1 = new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token;
// 두 번째 CancellationTokenSource를 생성하고 특정 시간(여기서는 4초) 이후에 취소될 토큰을 만듭니다.
var token2 = new CancellationTokenSource(TimeSpan.FromSeconds(4)).Token;
// 두 토큰을 결합하여 새로운 CancellationToken을 만듭니다.
var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(token1, token2).Token;
// 비동기 작업 시작
var task = Task.Run(() =>
{
while (!combinedToken.IsCancellationRequested)
{
// 작업 수행 중...
Console.WriteLine("Working...");
Thread.Sleep(1000);
}
}, combinedToken);
try
{
// 하나의 토큰이라도 취소되면 OperationCanceledException 예외 발생
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was canceled.");
}
}
}
이 코드는 두 개의 CancellationToken을 생성하고, 이 두 토큰을 CreateLinkedTokenSource를 사용하여 결합하여 하나의 토큰을 만드는 방법입니다. 결합된 토큰은 하나의 토큰이라도 취소되면 작업이 취소되는 기능을 갖고 있습니다.
| 취소 예외 처리
- 코드 예시에서 보면 공통된 부분이 있는 것을 확인할 수 있습니다.
try
{
await task; // 작업이 취소될 때 OperationCanceledException 예외 발생
}
catch (OperationCanceledException)
{
// 취소된 작업에 대한 추가 처리
Console.WriteLine("Task was canceled.");
// 여기에서 필요한 작업을 수행할 수 있습니다.
}
- CancellationToken을 사용하여 작업을 취소할 때 operationCanceledException이 발생하는데
이 예외는 비동기 작업이 취소된 상황에서 예외를 처리할 수 있게 도와줍니다.
이를 통해 안전한 종료나 로그를 찍어 필요한 조치를 취할 수 있게 됩니다.
| 마치며
- 프로젝트를 진행하면서 자주 썼던 비동기 작업에 대한 처리를 정리하다 보니
모르는 부분도 확인할 수 있었고 구조를 짤 때의 아이디어를 더 얻을 수 있었습니다.
작업을 효율적으로 하기 위한 비동기 작업에서 CancellationToken을 적절히 사용해 보는 것은 어떠신가요?
틀린 점이나 질문이 있으시면 댓글로 남겨주시고
다음 포스팅으로 찾아오겠습니다.
감사합니다 :)
'C#' 카테고리의 다른 글
C# 이벤트 발생 (Event Raising) 이해 (0) | 2023.10.31 |
---|---|
자동 구현 속성 이해 (Auto-implemented Properties) (0) | 2023.10.30 |
[C#] Marshal.Copy 이해 (0) | 2023.09.26 |
[C#] Bitmap.Clone() vs new Bitmap() 비교 (0) | 2023.09.26 |
[C#] Bitmap.LockBits 메서드 (0) | 2023.09.25 |