Home 4. Task_2
Post
Cancel

4. Task_2

Build Up

Action/Func - Task - async/await

Waiting for one or more tasks to complete

  • task는 일반적으로 thread pool의 thread에서 비동기적으로 실행되기 때문에
    task를 생성하고 시작하는 thread는 task가 인스턴스화되는 즉시 실행을 계속한다.
    • 실행 흐름을 계속 이어 간다는뜻
  • 경우에 따라 호출 스레드가 기본 응용 프로그램 스레드 인 경우
    작업이 실제로 실행되기 전에 앱이 종료 될 수 있다.
    • Task_1에서 Wait();를 빼고 실행하면 볼 수 있음.
  • 다른 경우에는 응용 프로그램의 논리에서
    호출 thread가 하나 이상의 작업이 실행을 완료 한 경우에만
    실행을 계속하도록 요구할 수 있다.
    하나 이상의 작업이 완료 될 때까지 대기하는 Wait 메서드를 호출하여
    호출 thread의 실행과 시작되는 비동기 작업을 동기화 할 수 있다.
  • 단일 작업이 완료 될 때까지 기다리려면 해당 Task.Wait 메서드를 호출.
    Wait 메서드에 대한 호출은 단일 클래스 인스턴스가
    실행을 완료 할 때까지 호출 thread를 block.

Wait()

  • Wait() method로 task가 끝날 떄까지 무조건 대기
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    class Status
    {
        public Status()
        {
            mtd_1();
        }
          
        void mtd_1()
        {
            Random rand = new Random();
            // Wait on a single task with no timeout specified.
            Task taskA = Task.Run(() => Thread.Sleep(2000));
            Console.WriteLine("taskA Status: {0}", taskA.Status);
            Thread.Sleep(1500);
            try
            {
                Console.WriteLine("taskA Status: {0}", taskA.Status);
                taskA.Wait();
                Console.WriteLine("taskA Status: {0}", taskA.Status);
            }
            catch (AggregateException)
            {
                Console.WriteLine("Exception in taskA.");
            }
        }
        //taskA Status: WaitingToRun
        //taskA Status: Running
        //taskA Status: RanToCompletion
    }
    
  • 작업이 완료 될 때까지 조건부로 기다릴 수도 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    class WaitCondition
    {
        public WaitCondition()
        {
            mtd_1();
        }
    
        void mtd_1()
        {
            // Wait on a single task with a timeout specified.
            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.");
            }
        }
        //Task A completed: False, Status: Running
        //Timed out before task A completed.
    }
    
    • Wait(Int32)및 Wait(TimeSpan) 메서드는
      작업이 완료 되거나 시간 제한 간격이 경과할 때까지
      (둘 중 먼저 도달 하는 경우) 호출 스레드를 차단.
    • 위에서는 2 초 동안 대기 하지만
      1 초 제한 시간 값을 정의 하는 task를 시작 하므로,
      호출 스레드는 제한 시간이 만료 될 때까지 차단 되고
      task 실행이 완료 되기 전까지 차단.

WaitAny()

  • 다수 task에서 하나의 끝을 기다릴떄
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    
    class WaitAny
    {
    
        public WaitAny()
        {
            mtd_1();
        }
    
        void mtd_1()
        {
            var tasks = new Task[3];
            var rnd = new Random();
            for (int ctr = 0; ctr <= 2; ctr++)
                tasks[ctr] = Task.Run(() => Thread.Sleep(rnd.Next(500, 3000)));
    
            try
            {
                int index = Task.WaitAny(tasks);
                Console.WriteLine("Task #{0} completed first.\n", tasks[index].Id);
                Console.WriteLine("Status of all tasks:");
                foreach (var t in tasks)
                    Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
            }
            catch (AggregateException)
            {
                Console.WriteLine("An exception occurred.");
            }
        }
    
        //Task #1 completed first.
    
        //Status of all tasks:
        //   Task #3: Running
        //   Task #1: RanToCompletion
        //   Task #4: Running
    }
    
    • 여러 task중 끝나는 task가 나올때 까지 기다림.
    • 등록된 task중 어떤것이든 상관없고 끝나는것만 알면 되는듯.

WaitAll()

  • 다수 task의 전체 종료를 기다릴떄
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
      class WaitAll
      {
          public WaitAll()
          {
              mtd_1();
          }
    
          void mtd_1()
          {
              // Wait for all tasks to complete.
              Task[] tasks = new Task[10];
              for (int i = 0; i < 10; i++)
              {
                  tasks[i] = Task.Run(() => Thread.Sleep(2000));
              }
              try
              {
                  Task.WaitAll(tasks);
              }
              catch (AggregateException ae)
              {
                  Console.WriteLine("One or more exceptions occurred: ");
                  foreach (var ex in ae.Flatten().InnerExceptions)
                      Console.WriteLine("   {0}", ex.Message);
              }
    
              Console.WriteLine("Status of completed tasks:");
              foreach (var t in tasks)
                  Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
          }
         //Status of completed tasks:
         //Task #10: RanToCompletion
         //Task #9: RanToCompletion
         //Task #8: RanToCompletion
         //Task #7: RanToCompletion
         //Task #2: RanToCompletion
         //Task #5: RanToCompletion
         //Task #4: RanToCompletion
         //Task #6: RanToCompletion
         //Task #3: RanToCompletion
         //Task #1: RanToCompletion
      }
    

throw

  • 하나 이상의 작업이 완료 될 때까지 대기 하는 경우
    실행 중인 task에서 throw 되는 모든 예외가
    wait()을 호출 하는 thread로 전파됨.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    
    class Task_4
    {
        public Task_4()
        {
            var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            var files = new List<Tuple<string, string, long, DateTime>>();
    
            var t = new Task(() => {
                string dir = "C:\\Windows\\System32\\";
                object obj = new Object();
                if (Directory.Exists(dir))
                {
                    Parallel.ForEach(Directory.GetFiles(dir),
                    f => {
                        if (token.IsCancellationRequested)
                            token.ThrowIfCancellationRequested();
                        var fi = new FileInfo(f);
                        lock (obj)
                        {
                            files.Add(Tuple.Create(fi.Name, fi.DirectoryName, fi.Length, fi.LastWriteTimeUtc));
                        }
                    });
                }
            }, token);
            t.Start();
            tokenSource.Cancel();
            try
            {
                //await t;
                Console.WriteLine("Retrieved information for {0} files.", files.Count);
            }
            catch (AggregateException e)
            {
                Console.WriteLine("Exception messages:");
                foreach (var ie in e.InnerExceptions)
                    Console.WriteLine("   {0}: {1}", ie.GetType().Name, ie.Message);
    
                Console.WriteLine("\nTask status: {0}", t.Status);
            }
            finally
            {
                tokenSource.Dispose();
            }
        }
        //One or more exceptions occurred:
        //   TaskCanceledException: 작업이 취소되었습니다.
        //   NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   TaskCanceledException: 작업이 취소되었습니다.
        //   TaskCanceledException: 작업이 취소되었습니다.
        //   NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   TaskCanceledException: 작업이 취소되었습니다.
        //   TaskCanceledException: 작업이 취소되었습니다.
        //   NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   TaskCanceledException: 작업이 취소되었습니다.
    
        //Status of tasks:
        //   Task #12: RanToCompletion
        //   Task #1: Canceled
        //   Task #9: Faulted
        //      NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   Task #14: Canceled
        //   Task #10: RanToCompletion
        //   Task #2: Canceled
        //   Task #7: Faulted
        //      NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   Task #15: Canceled
        //   Task #11: RanToCompletion
        //   Task #3: Canceled
        //   Task #8: Faulted
        //      NotSupportedException: 지정한 메서드가 지원되지 않습니다.
        //   Task #13: Canceled
    }
    
    
    • task 12 개.
    • 이 중 3 개는 정상적으로 완료
      3 개는 예외를 throw.
      나머지 6 개 작업 중 3 개는 시작 하기 전에 취소
      3은 실행 중에 취소.
    • 예외는 WaitAll호출 method로 throw 되며
      try/catch 블록에 의해 처리.

Other Wait

Task

  • 이번엔 return이 있는경우
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    class test_2
    {
        public test_2()
        {
            Func<object, int> func;
            func = mtd;
    
            Task<int> t1 = new Task<int>(func,1);
            t1.Start();
            Console.WriteLine(t1.Result);
    
            Task<int> t = Task<int>.Run(() => {
                // Just loop.
                int max = 1000000;
                int ctr = 0;
                for (ctr = 0; ctr <= max; ctr++)
                {
                    if (ctr == max / 2 && DateTime.Now.Hour <= 12)
                    {
                        ctr++;
                        break;
                    }
                }
                return ctr;
            });
            Console.WriteLine("Finished {0:N0} iterations.", t.Result);   
        }
    
        int mtd(object _i)
        {
            return (int)_i + 1;
        }
    }
    
    • 두 가지 경우를 보임.
      • parameter 하나 넘기고 return 받는 경우(t1)
      • paramerer없이 return 받는 경우(t)
    • 근데 t의 경우 wait가 없는데 어떤 경우건 정상적으로 끝남 (지금까지는).
      run()다음 cw부분때문인것같음…

참고

This post is licensed under CC BY 4.0 by the author.

3. Task_1

5. async/await_1 (sync/async, block/non-block)

Comments powered by Disqus.