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 실행이 완료 되기 전까지 차단.
- Wait(Int32)및 Wait(TimeSpan) 메서드는
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.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부분때문인것같음…
- 두 가지 경우를 보임.
Comments powered by Disqus.