이 내용은 msdn에 내용을 발췌 한 것입니다.
(
https://docs.microsoft.com/ko-kr/dotnet/standard/parallel-programming/task-based-asynchronous-programming)
Task를 생성 할 때는 Task에서 실행 할 코드를 캡슐화하는 사용자 대리자를 지정해야 합니다. 대리자는:
으로 표현할 수 있습니다.
- Task 생성
1: static void Main(string[] args)
2: {
3: Thread.CurrentThread.Name = "Main";
4: // lambda expression을 이용한 Task 생성
5: Task taskA = new Task(() => Console.WriteLine("Hello from taskA"));
6: // Task 시작
7: taskA.Start();
8: // 호출 쓰레드에서 출력한 메시지
9: Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);
10: // 응용 프로그램이 종료되기 전에 작업 실행이 완료되도록 Task.Wait 메소드에 호출
11: taskA.Wait();
12: Console.ReadKey();
13: }
14: // The example displays output like the following:
15: // Hello from thread 'Main'.
16: // Hello from taskA.
- 한 번에 작업을 만들고 시작
1: static void Main(string[] args)
2: {
3: Thread.CurrentThread.Name = "Main";
4: // Task를 지정하고 바로 실행
5: Task taskA = Task.Run(() => Console.WriteLine("Hello from taskA"));
6: // 호출 쓰레드에서 출력한 메시지
7: Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);
8: //응용 프로그램이 종료되기 전에 작업 실행이 완료되도록 Task.Wait 메소드에 호출
9: taskA.Wait();
10: Console.ReadKey();
11: }
12: // The example displays output like the following:
13: // Hello from thread 'Main'.
14: // Hello from taskA.
- TaskFactory.StartNew 메서드를 사용하여 한 번에 작업을 만들고 시작
1: class CustomData
2: {
3: public long CreationTime;
4: public int Name;
5: public int ThreadNum;
6: }
7: /// <summary>
8: /// TaskFactory.StartNew 메서드를 사용하여 한 번에 작업을 만들고 시작할 수도 있습니다:
9: /// - 생성 및 일정 예약을 구분할 필요가 없고
10: /// - 추가 작업 생성 옵션이나 특정 스케줄러를 사용할 필요가 있는 경우
11: /// - Task.AsyncState 속성을 통해 검색할 수 있는 작업에 추가 상태를 전달해야 하는 경우
12: /// 이 메서드를 사용합니다.
13: /// </summary>
14: /// <param name="args"></param>
15: static void Main(string[] args)
16: {
17: Thread.CurrentThread.Name = "Main";
18: Task[] taskArray = new Task[10];
19: for (int i = 0; i < taskArray.Length; i++)
20: {
21: taskArray[i] = Task.Factory.StartNew((Object o) =>
22: {
23: CustomData data = o as CustomData;
24: if (data == null) return;
25: data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
26: },
27: new CustomData
28: {
29: Name = i,
30: CreationTime = DateTime.Now.Ticks
31: });
32: }
33: Task.WaitAll(taskArray);
34: foreach (var task in taskArray)
35: {
36: var data = task.AsyncState as CustomData;
37: if (data != null)
38: Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
39: data.Name, data.CreationTime, data.ThreadNum);
40: }
41: Console.ReadKey();
42: }
43: // The example displays output like the following:
44: // Task #0 created at 635116412924597583 on thread #3.
45: // Task #1 created at 635116412924607584 on thread #4.
46: // Task #3 created at 635116412924607584 on thread #4.
47: // Task #4 created at 635116412924607584 on thread #4.
48: // Task #2 created at 635116412924607584 on thread #3.
49: // Task #6 created at 635116412924607584 on thread #3.
50: // Task #5 created at 635116412924607584 on thread #4.
51: // Task #8 created at 635116412924607584 on thread #4.
52: // Task #7 created at 635116412924607584 on thread #3.
53: // Task #9 created at 635116412924607584 on thread #4.
- System.Threading.Tasks.Task<TResult> 형식으로 값을 반환
1: /// <summary>
2: /// System.Threading.Tasks.Task<TResult> 형식이므로 값을 반환하는 예제 입니다.
3: /// 작업은 비동기적으로 실행되며 완료 순서에는 제한이 없습니다.
4: /// 계산이 완료되기 전에 Result 속성에 액세스할 경우, 이 속성이 값을 사용할 수 있을 때까지 호출 스레드를 차단 합니다
5: /// </summary>
6: /// <param name="args"></param>
7: static void Main(string[] args)
8: {
9: Task<Double>[] taskArray =
10: {
11: Task<Double>.Factory.StartNew(() => DoComputation(1.0)),
12: Task<Double>.Factory.StartNew(() => DoComputation(100.0)),
13: Task<Double>.Factory.StartNew(() => DoComputation(1000.0))
14: };
15: var results = new Double[taskArray.Length];
16: Double sum = 0;
17: for (int i = 0; i < taskArray.Length; i++)
18: {
19: // 계산이 완료되기 전에 Result 속성에 액세스할 경우, 이 속성이 값을 사용할 수 있을 때까지 호출 스레드를 차단
20: results[i] = taskArray[i].Result;
21: Console.Write("{0:N1} {1}", results[i],
22: i == taskArray.Length - 1 ? "= " : "+ ");
23: sum += results[i];
24: }
25: Console.WriteLine("{0:N1}", sum);
26: Console.ReadKey();
27: }
28: // The example displays the following output:
29: // 606.0 + 10,605.0 + 100,495.0 = 111,706.0
30: private static Double DoComputation(Double start)
31: {
32: Double sum = 0;
33: for (var value = start; value <= start + 10; value += .1)
34: {
35: sum += value;
36: }
37: return sum;
38: }
# 반목문 사용시 TaskFactory.StartNew 메서드 사용시 발생할 수 있는 문제 예
루프 카운터를 TaskFactory.StartNew 메서드의 Task.AsyncState 속성을 이용해 전달 할 경우 람다는 각 반복의 변경된 값이 아닌 최종 값만 capture 합니다.
아래와 같이 동일한 식별자가 나오는 것을 볼 수 있습니다.
1: /// <summary>
2: /// 반복문을 사용하여 TaskFactory.StartNew 메서드를 사용하여 한 번에 작업을 만들고 시작할 경우 발생될 수 있는 문제:
3: /// - 람다는 각 반복 후에 변경할 때 값이 아닌 최종 값만 capture 합니다.
4: /// </summary>
5: /// <param name="args"></param>
6: static void Main(string[] args)
7: {
8: Task[] taskArray = new Task[10];
9: for (int i = 0; i < taskArray.Length; i++)
10: {
11: // 문제 발생! - 변경 되는 i 변수의 최종 값만 캡처 한다
12: taskArray[i] = Task.Factory.StartNew((Object obj) => {
13: var data = new CustomData() { Name = i, CreationTime = DateTime.Now.Ticks };
14: data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
15: Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
16: data.Name, data.CreationTime, data.ThreadNum);
17: },
18: i);
19: }
20: Task.WaitAll(taskArray);
21: Console.ReadKey();
22: }
23: // The example displays output like the following:
24: // Task #10 created at 635116418427727841 on thread #4.
25: // Task #10 created at 635116418427737842 on thread #4.
26: // Task #10 created at 635116418427737842 on thread #4.
27: // Task #10 created at 635116418427737842 on thread #4.
28: // Task #10 created at 635116418427737842 on thread #4.
29: // Task #10 created at 635116418427737842 on thread #4.
30: // Task #10 created at 635116418427727841 on thread #3.
31: // Task #10 created at 635116418427747843 on thread #3.
32: // Task #10 created at 635116418427747843 on thread #3.
33: // Task #10 created at 635116418427737842 on thread #4.
위와 같은 문제를 해결하려면 위 샘플 예제 "TaskFactory.StartNew 메서드를 사용하여 한 번에 작업을 만들고 시작" 와 같이 AsyncState 매개 변수로 생성자를 통한 상태 객체를 생성하여 각 반복값에 액세스 할 수 있습니다.
댓글
댓글 쓰기