반응형
internal class Program
{
static int TaskMethod(string name, int second)
{
DateTime now = DateTime.Now;
string formattedTime = now.ToString("HH:mm:s:fff");
Console.WriteLine($"[{formattedTime}] " + "Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(second));
return 42 * second;
}
static void Main(string[] args)
{
var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
DateTime now = DateTime.Now;
string formattedTime = now.ToString("HH:mm:s:fff");
firstTask.ContinueWith(
t => Console.WriteLine($"[{formattedTime}] " + "The first answer is {0}, Thread id {1}, is thread pool thread: {2}",
t.Result,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread),
TaskContinuationOptions.OnlyOnRanToCompletion
);
firstTask.Start();
secondTask.Start();
Thread.Sleep(TimeSpan.FromSeconds(4));
now = DateTime.Now;
formattedTime = now.ToString("HH:mm:s:fff");
Task continuation = secondTask.ContinueWith(
t => Console.WriteLine($"[{formattedTime}] " + "The second answer is {0}, Thread id {1}, is thread pool thread: {2}",
t.Result,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread),
TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);
now = DateTime.Now;
formattedTime = now.ToString("HH:mm:s:fff");
continuation.GetAwaiter().OnCompleted(
() => Console.WriteLine($"[{formattedTime}] " + "Continuation Task Completed! Thread id {0}, is thread pool thread: {1}",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread)
);
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine();
firstTask = new Task<int>(() =>
{
var innerTask = Task.Factory.StartNew(() => TaskMethod("Second Task", 5), TaskCreationOptions.AttachedToParent);
innerTask.ContinueWith(t => TaskMethod("Third Task", 2), TaskContinuationOptions.AttachedToParent);
return TaskMethod("First Task", 2);
});
firstTask.Start();
while (!firstTask.IsCompleted)
{
now = DateTime.Now;
formattedTime = now.ToString("HH:mm:s:fff");
Console.WriteLine($"[{formattedTime}] " + firstTask.Status);
Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
now = DateTime.Now;
formattedTime = now.ToString("HH:mm:s:fff");
Console.WriteLine($"[{formattedTime}] " + firstTask.Status);
Thread.Sleep(TimeSpan.FromSeconds(10));
}
}
태스크(Task)에 대한 정리
개요
- 이 코드는 C#의 Task(태스크)와 비동기 처리 기법을 활용하여 독립적인 태스크 생성, 연속(continuation) 작업, 부모-자식 관계 태스크 등을 학습하기 위한 예제입니다.
- 주요 학습 포인트:
- 독립적인 태스크 생성 및 실행.
- 선행 작업 완료 후 실행되는 연속 작업.
- 태스크 연속 작업의 동기적 실행.
- 비동기 프로그래밍과 OnCompleted 사용.
- 부모-자식 관계 태스크의 동작.
코드 분석
1. 독립적인 태스크 생성 및 실행
- 두 개의 독립적인 태스크를 생성합니다.
var firstTask = new Task<int>(() => TaskMethod("First Task", 3)); var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
- 각 태스크는 별도의 스레드에서 실행되며, 서로 간섭하지 않습니다.
- TaskMethod는 태스크의 이름, 실행 시간, 스레드 정보를 출력하며, 결과(42 * 실행 시간)를 반환합니다.
2. 태스크 연속 작업 설정
- ContinueWith를 사용하여 태스크가 완료된 후 실행할 연속 작업을 정의합니다.
firstTask.ContinueWith( t => Console.WriteLine("The first answer is {0}, Thread id {1}, is thread pool thread: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion );
- OnlyOnRanToCompletion 옵션을 사용하여 선행 작업이 성공적으로 완료된 경우에만 실행합니다.
3. 태스크 시작 및 대기
- 두 태스크를 시작하고, Thread.Sleep으로 4초 동안 대기하여 태스크들이 종료될 시간을 줍니다.
firstTask.Start(); secondTask.Start(); Thread.Sleep(TimeSpan.FromSeconds(4));
4. 동기적 연속 작업
- secondTask에 대해 연속 작업을 추가하며, TaskContinuationOptions.ExecuteSynchronously 옵션을 지정합니다.
Task continuation = secondTask.ContinueWith( t => Console.WriteLine("The second answer is {0}, Thread id {1}, is thread pool thread: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously );
- ExecuteSynchronously: 연속 작업이 새로운 스레드 대신 현재 실행 중인 스레드에서 동기적으로 실행됩니다.
- 짧은 수명의 작업일 경우 성능 최적화를 위해 유용합니다.
5. OnCompleted 사용
- GetAwaiter().OnCompleted를 통해 태스크 완료 후 실행할 코드를 정의합니다.
continuation.GetAwaiter().OnCompleted( () => Console.WriteLine("Continuation Task Completed! Thread id {0}, is thread pool thread: {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread) );
- 비동기 작업 완료 후 추가적인 처리를 수행합니다.
6. 부모-자식 관계 태스크
- 새로운 부모 태스크를 생성하며, 내부에서 자식 태스크를 실행합니다.
firstTask = new Task<int>(() => { var innerTask = Task.Factory.StartNew(() => TaskMethod("Second Task", 5), TaskCreationOptions.AttachedToParent); innerTask.ContinueWith(t => TaskMethod("Third Task", 2), TaskContinuationOptions.AttachedToParent); return TaskMethod("First Task", 2); });
- TaskCreationOptions.AttachedToParent:
- 자식 태스크가 부모 태스크와 연결됩니다.
- 부모 태스크는 자식 태스크들이 모두 완료될 때까지 종료되지 않습니다.
- 자식 태스크는 Second Task와 Third Task를 실행합니다.
- TaskCreationOptions.AttachedToParent:
실행 결과 예상
1. 각 태스크 실행
- TaskMethod가 실행되며 태스크의 이름, 실행 시간, 스레드 정보를 출력합니다.
[14:12:34:123] Task First Task is running on a thread id 5. Is thread pool thread: True [14:12:34:456] Task Second Task is running on a thread id 6. Is thread pool thread: True
2. 연속 작업 실행
- firstTask와 secondTask 완료 후 각각의 연속 작업이 실행됩니다.
[14:12:37:123] The first answer is 126, Thread id 7, is thread pool thread: True [14:12:36:456] The second answer is 84, Thread id 6, is thread pool thread: True
3. OnCompleted 실행
- OnCompleted 메서드가 호출되어 연속 작업 완료 후 메시지를 출력합니다.
[14:12:36:789] Continuation Task Completed! Thread id 6, is thread pool thread: True
4. 부모-자식 태스크 실행
- 부모 태스크가 완료되기 전에 자식 태스크(Second Task, Third Task)가 실행됩니다.
[14:12:39:123] Task Second Task is running on a thread id 8. Is thread pool thread: True [14:12:44:456] Task Third Task is running on a thread id 9. Is thread pool thread: True [14:12:46:789] Task First Task is running on a thread id 8. Is thread pool thread: True
5. 태스크 상태 출력
- 부모 태스크의 상태를 지속적으로 확인하며 출력합니다.
[14:12:40:000] Running [14:12:41:000] Running ... [14:12:46:789] RanToCompletion
학습 포인트
- 독립적인 태스크 생성 및 실행:
- Task를 사용하여 비동기 작업을 독립적으로 실행할 수 있다.
- 연속 작업:
- ContinueWith를 통해 선행 작업 완료 후 실행할 작업을 정의할 수 있다.
- 동기적 연속 작업:
- 짧은 작업을 동기적으로 처리하여 스레드 풀 부담을 줄이고 성능을 최적화한다.
- 비동기 기법 통합:
- OnCompleted를 활용하여 비동기 프로그래밍과 태스크 연속 작업을 결합한다.
- 부모-자식 태스크 관계:
- 자식 태스크가 완료될 때까지 부모 태스크가 종료되지 않는 구조를 이해한다.
결론
이 코드는 C#에서 Task와 비동기 처리 기법을 학습하기에 적합한 예제입니다. 태스크 생성, 연속 작업 설정, 동기적 실행, 부모-자식 태스크 관리 등의 개념을 이해하는 데 큰 도움이 됩니다. 추가 질문이나 특정 부분에 대한 설명이 필요하면 알려주세요!
반응형
'C# > 쓰레드' 카테고리의 다른 글
1. C# 스레드 생성과 병렬 처리 이해 (0) | 2025.01.24 |
---|---|
4. 태스크 병렬 라이브러리 (0) | 2025.01.20 |
C# Task 기본 동작과 스레드 실행 시나리오 이해 (12) | 2025.01.17 |
C# TPL: 태스크 생성 방식과 실행 흐름 완벽 이해 (0) | 2025.01.17 |
C# `Thread`와 `ThreadPool`의 차이점 및 델리게이트 비동기 호출 이해 (16) | 2025.01.16 |
C# 스레드풀(Thread Pool): 개념, 사용법, 및 예제 코드 설명 (1) | 2025.01.16 |
C# SemaphoreSlim: 멀티스레드 리소스 접근 제어 예제와 설명 (1) | 2025.01.16 |
C# 스레드 제어: Semaphore와 SemaphoreSlim의 차이와 사용법 (0) | 2025.01.16 |