[WPF] 공공데이터 포털 API 이용 클라이언트 구현 Part 3

이미지
그룹핑 ListViewItem 그룹핑 할 수 있습니다. 먼저 CheckBox에 Checked 이벤트를 통해 그룹핑을 추가하고 RemoveChecked 이벤트를 통해 그룹핑을 제거 할 수 있도록 CheckBox를 선언 합니다. 1: <!-- Group CheckBox --> 2: <CheckBox Grid.Column="0" 3: Grid.Row="0" 4: Checked="AddGrouping" 5: Unchecked="RemoveGrouping">Group by Name</CheckBox> 그룹 스타일 선언 GroupStyle 속성에 ContainerStyle 속성을 이용해 Style을 지정 합니다. Expander 컨트롤을 이용해 아파트명과 그룹 아이템의 개수를 Expander Header에 표시 하도록 ControlTemlate를 선언 합니다. 1: <!-- Group Style --> 2: <ListView.GroupStyle> 3: <GroupStyle> 4: <GroupStyle.ContainerStyle> 5: <Style TargetType="{x:Type GroupItem}"> 6: <Setter Property="Margin" Value="0,0,0,5" /> 7: <Setter Property="Te...

[C#] 명시적으로 Task 생성 및 실행

이 내용은 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 매개 변수로 생성자를 통한 상태 객체를 생성하여 각 반복값에 액세스 할 수 있습니다.

댓글

이 블로그의 인기 게시물

[C#] Task 완료 시 다른 Task를 자동으로 수행

[C#] 태스크(Task)가 완료될 때 까지 대기하여 결과를 얻는 방법