Task Property
코드 리팩토링을 진행하면서, 내 과거의 코드가 굉장히 창피했다. C#을 1년간 썼으나, 늘어나는 건 그저 수많은 if문과 while문,,, Thread.Sleep이 다였다. 소켓통신을 통해 메세지를 주고받는데, 이걸 Request/Response 형식의 API로 구현했다. 메세지를 Send한 뒤 기다리는 과정에서 While문을 통해 그저 기다리며 해당 메세지를 수신 시 Return하는 형식으로 구현했었다. 코드 리팩토링을 하는 과정에서 TAP
를 알게 되었고, 이제 정리해보려 한다.
TAP
우선 비동기 프로그래밍을 다루는 것은 굉장히 중요하다.
가령 프로그램 내에서 용량이 제법 큰 파일을 다운로드 한 후 처리하는 작업이 있다고 하자.
동기적으로 프로그래밍을 한다면 파일을 다운로드할때까지 무작정 기다린 후 해당 결과값을 가지고 후속작업을 진행한다. 그 와중 UI 같은 것들이 Blocking 상태로 있을 수 있다. 그래서 우린 비동기적으로 프로그램을 짜려 한다.
Task
Task클래스는 값을 반환 하지 않고 비동기적으로 실행되는 단일 작업을 나타냅니다.
Task개체는 .NET Framework4에서 처음 도입된 작업 기반 비동기 패턴의 중심 구성 요소 중 하나입니다.
메인 어플리케이션 쓰레드에서 동기적으로 실행되기 보단, 쓰레드풀에서 비동기적으로 작업이 실행되기 때문에,
Task의 상태를 결정하기 위해 Status 속성과 IsCanceled, IsCompleted, IsFaulted 속성을 사용할 수 있습니다.
일반적으로 task 수행을 위해 람다 표현식이 사용됩니다.
return value가 필요하면 Task<TResult> 클래스를 사용하면 됩니다.
짧은 영어실력으로 https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=net-5.0 에 있는 글을 번역해봤다. 가끔 한국어로 보면 번역이 이상해서 영어로 바꿔서 꾸역꾸역 읽는다..
Task 인스턴스 만들기
Task를 인스턴스화 하고 실행하는 4가지 방법이 있다.
1. Task 생성자로 만들고 Start로 시작
2. 생성과 시작 동시에 하기
3. Run() 메소드로 생성과 시작
4. RunSynchronously() 메소드로 동기적 실행
// Task 생성자로 만들고 Start호출해서 시작하기
Action<object> action = (object obj) =>
{
Console.WriteLine("Task={0}, obj={1}, Thread={2}",
Task.CurrentId, obj,
Thread.CurrentThread.ManagedThreadId);
};
Task t1 = new Task(action, "alpha");
t1.Start(); // Task 시작
// 생성과 시작을 동시에 하기
Task t2 = Task.Factory.StartNew(action, "beta");
// Run(Action) 메소드로 인스턴스 생성과 시작
Task t3 = Task.Run( () => {Console.WriteLine("Task={0}, obj={1}, Thread={2}",
Task.CurrentId, taskData,
Thread.CurrentThread.ManagedThreadId);
});
// RunSynchronously() 메소드로 메인스레드에서 동기적으로 실행
Task t4 = new Task(action,"gamma");
t4.RunSynchronously();
개인적으로 4번째 방법은 잘 안쓸것같다.
우선 C#의 Task
클래스에 어떤 속성과 메서드가 있는지 알아보장
Properties
- IsCanceled
- IsCompleted
- IsCompletedSuccessfully (.NET 5.0부터 지원)
- IsFaulted
IsCanceled
Task가 Cancel 행위 때문에 완료되었다면 true, 아니면 false 반환CancellationToken
을 이용하면 Task를 취소할 수 있다.
IsCompleted
Task가 완료되면 true, 아니면 false
인데, Task 완료 상태는 총 3가지가 있음. RanToCompletion
, Faulted
, Canceled
즉, 만약 Task가 Exception이 나서 실패되거나, 취소되어도 IsCompleted는 true를 반환한다.
만일 Task가 정상 수행됐는지를 따져보려면 IsCompleted하나만 봐서 판별할 순 없고, Faulted된건지 Cancel인지, RanToCompletion인지를 따져봐야함
IsCompletedSuccessfully
위에서 정상수행인지 따지려면 Fault인지 Cancel인지도 따져봐야 한다고 했는데, 이걸 쓰면 그런거 신경안쓰고 잘 완료되었는지 확인할 수 있음. 근데 .NET 5.0에만 있는거같다. 예전 버전엔 안나옴
IsFaulted
Task수행중 Exception나면 true인데, Task에 또 Exception
이라는 속성이 있다. 그래서 만약 Fault나면 Exception속성은 null이 아닐것이다.
Task taskA = Task.Run( () => Thread.Sleep(2000));
try {
taskA.Wait(1000); // Wait for 1 second.
bool completed = taskA.IsCompleted;
Console.WriteLine("Task A completed: {0}, Status: {1}",
completed, taskA.Status);
if (! completed)
Console.WriteLine("Timed out before task A completed.");
}
catch (AggregateException) {
Console.WriteLine("Exception in taskA.");
}
2초간 Sleep하는 Task가 있다. 이걸 Task.Run으로 실행한 뒤, taskA가 끝나기까지 1초간 기다린다. (Task가 1초 안에 끝나면 바로 풀림. 일종의 타임아웃)
그 후 taskA가 완료되었는지 체크하는.. 그런 간단한 코드였다.
Task Property에 대해 간략히 알아봤는데, 다음엔 Method에 대해 알아볼 것이다.