[C#/TPL/.NET8] Task 클래스 : ConfigureAwait 메소드를 사용해 await 이후 스레드 풀 스레드에서 실행하기
■ Task<T> 클래스의 ConfigureAwait 메소드를 사용해 await 이후 스레드 풀 스레드에서 실행하는 방법을 보여준다. ※ 기본적으로 async/await 패턴은 작업이 완료된 후 원래의
■ Task<T> 클래스의 ConfigureAwait 메소드를 사용해 await 이후 스레드 풀 스레드에서 실행하는 방법을 보여준다. ※ 기본적으로 async/await 패턴은 작업이 완료된 후 원래의
■ Task 클래스를 사용해 완료된 작업을 만드는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System.Threading.Tasks; #region 완료된 태스크 구하기 - GetCompletedTask() /// <summary> /// 완료된 태스크 구하기 /// </summary> /// <returns>태스크</returns> public Task GetCompletedTask() { return new Task(() => { }); } #endregion |
■ Task 클래스의 FromResult 정적 메소드를 모방하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Threading.Tasks; #region 작업 결과 구하기 - FromResult<TResult>(resultValue) /// <summary> /// 작업 결과 구하기 /// </summary> /// <typeparam name="TResult">결과 타입</typeparam> /// <param name="resultValue">결과 값</param> /// <returns>작업 결과</returns> public Task<TResult> FromResult<TResult>(TResult resultValue) { TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>(); source.SetResult(resultValue); return source.Task; } #endregion |
■ Task 클래스의 FromResult 정적 메소드를 사용해 완료된 작업을 만드는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Threading.Tasks; /// <summary> /// 완료된 태스크 /// </summary> private static Task _completedTask = Task.FromResult(false); #region 완료된 태스크 구하기 - GetCompletedTask() /// <summary> /// 완료된 태스크 구하기 /// </summary> /// <returns>태스크</returns> public static Task GetCompletedTask() { return _completedTask; } #endregion |
■ Task 클래스의 CompletedTask 정적 속성을 사용해 완료된 작업을 만드는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 |
using System.Threading.Tasks; Task completedTask = Task.CompletedTask; |
■ Task 클래스 : WhenAll 정적 메소드를 사용해 모든 태스크 작업 완료를 대기하는 방법을 보여준다. ▶ Program.cs
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 |
namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private async static Task Main() { string[] sourceArray = new string[] { "London", "New York", "Paris", "Seoul", "Tokyo" }; List<Task> taskList = new List<Task>(); foreach(string source in sourceArray) { taskList.Add ( Task.Run ( async () => { await Task.Delay(1000); Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {source}"); } ) ); } await Task.WhenAll(taskList); } #endregion } |
TestProject.zip
■ Parallel 클래스의 ForEach 정적 메소드를 Task 클래스 Start 메소드에서 사용하는 방법을 보여준다. ▶ Program.cs
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 |
namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private async static Task Main() { string[] stringArray = new string[] { "London", "New York", "Paris", "Seoul", "Tokyo" }; await Task.Run ( () => Parallel.ForEach ( stringArray, async s => { await Task.Delay(1000); Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {s}"); } ) ); Console.ReadKey(false); } #endregion } |
TestProject.zip
■ Task 클래스에서 반복 작업자를 사용하는 방법을 보여준다. (기능 개선) ▶ RepeatWorker.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
using System; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 작업 반복자 /// </summary> public class RepeatWorker : IDisposable { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field (Private) /// <summary> /// 취소 토큰 소스 /// </summary> private CancellationTokenSource cancellationTokenSource = null; /// <summary> /// 건너뛰기 시간 (단위 : 밀리초) /// </summary> private int skipTime; /// <summary> /// 건너뛰기 시간 범위 /// </summary> private TimeSpan skipTimeSpan; /// <summary> /// 휴지 시간 (단위 : 밀리초) /// </summary> private int sleepTime = 1000; /// <summary> /// 휴지 시간 범위 /// </summary> private TimeSpan sleepTimeSpan; /// <summary> /// 작업 액션 /// </summary> private Action<object> workAction = null; /// <summary> /// 작업 매개 변수 /// </summary> private object workParameter = null; /// <summary> /// 실행 여부 /// </summary> private bool isRunning = false; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 건너뛰기 시간 (단위 : 밀리초) - SkipTime /// <summary> /// 건너뛰기 시간 (단위 : 밀리초) /// </summary> public int SkipTime { get { return this.skipTime; } set { this.skipTime = value; this.skipTimeSpan = TimeSpan.FromMilliseconds(this.skipTime); } } #endregion #region 휴지 시간 (단위 : 밀리초) - SleepTime /// <summary> /// 휴지 시간 (단위 : 밀리초) /// </summary> public int SleepTime { get { return this.sleepTime; } set { this.sleepTime = value; this.sleepTimeSpan = TimeSpan.FromMilliseconds(this.sleepTime); } } #endregion #region 작업 액션 - WorkAction /// <summary> /// 작업 액션 /// </summary> public Action<object> WorkAction { get { return this.workAction; } set { this.workAction = value; } } #endregion #region 작업 매개 변수 - WorkParameter /// <summary> /// 작업 매개 변수 /// </summary> public object WorkParameter { get { return this.workParameter; } set { this.workParameter = value; } } #endregion #region 실행 여부 - IsRunning /// <summary> /// 실행 여부 /// </summary> public bool IsRunning { get { return this.isRunning; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RepeatWorker() /// <summary> /// 생성자 /// </summary> public RepeatWorker() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 시작하기 - Start() /// <summary> /// 시작하기 /// </summary> public void Start() { this.cancellationTokenSource = new CancellationTokenSource(); _ = ExecuteWorkAsync(this.cancellationTokenSource.Token); } #endregion #region 중단하기 - Stop() /// <summary> /// 중단하기 /// </summary> public void Stop() { if(this.cancellationTokenSource != null) { this.cancellationTokenSource.Cancel(); this.cancellationTokenSource.Dispose(); this.cancellationTokenSource = null; } } #endregion #region 리소스 해제하기 - Dispose() /// <summary> /// 리소스 해제하기 /// </summary> public void Dispose() { Stop(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 비동기 작업 실행하기 - ExecuteWorkAsync() /// <summary> /// 비동기 작업 실행하기 /// </summary> /// <returns>태스크</returns> private Task ExecuteWorkAsync() { return Task.Run(()=> { this.workAction(this.workParameter); }); } #endregion #region 비동기 작업 실행하기 - ExecuteWorkAsync(cancellationToken) /// <summary> /// 비동기 작업 실행하기 /// </summary> /// <param name="cancellationToken">취소 토큰</param> /// <returns>태스크</returns> private async Task ExecuteWorkAsync(CancellationToken cancellationToken) { try { this.isRunning = true; await Task.Delay(this.skipTimeSpan, cancellationToken); while(true) { await ExecuteWorkAsync(); await Task.Delay(this.sleepTimeSpan, cancellationToken); } } catch(Exception) { } finally { this.isRunning = false; } } #endregion } } |
▶ MainForm.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
using System; using System.Threading; using System.Windows.Forms; namespace TestProject { /// <summary> /// 메인 폼 /// </summary> public partial class MainForm : Form { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 동기화 컨텍스트 /// </summary> private SynchronizationContext context; /// <summary> /// 반복 작업자 /// </summary> private RepeatWorker worker; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainForm() /// <summary> /// 생성자 /// </summary> public MainForm() { InitializeComponent(); this.context = SynchronizationContext.Current; this.worker = new RepeatWorker(); this.worker.SleepTime = 1000; this.worker.WorkParameter = "홍길동"; this.worker.WorkAction = (p) => { this.context.Send ( _ => { this.listBox.Items.Add($"{DateTime.Now.ToString("HH:mm:ss")} : {p}, {this.worker.IsRunning}"); }, null ); }; this.runButton.Click += runButton_Click; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 실행 버튼 클릭시 처리하기 - runButton_Click(sender, e) /// <summary> /// 실행 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void runButton_Click(object sender, EventArgs e) { if(this.runButton.Text == "실행") { this.runButton.Text = "중단"; this.worker.Start(); } else { this.runButton.Text = "실행"; this.worker.Stop(); Thread.Sleep(500); this.listBox.Items.Add($"{DateTime.Now.ToString("HH:mm:ss")} : {this.worker.WorkParameter}, {this.worker.IsRunning}"); } } #endregion } } |
TestProject.zip
■ Task 클래스의 Wait 메소드를 사용하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
using System; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> public class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 작업 1 실행하기 - ExecuteJob1() /// <summary> /// 작업 1 실행하기 /// </summary> private static void ExecuteJob1() { Thread.Sleep(20000); Console.WriteLine("JOB #1 EXECUTED"); } #endregion #region 작업 2 실행하기 - ExecuteJob2() /// <summary> /// 작업 2 실행하기 /// </summary> private static void ExecuteJob2() { Thread.Sleep(20000); Console.WriteLine("JOB #2 EXECUTED"); } #endregion #region 작업 3 실행하기 - ExecuteJob3() /// <summary> /// 작업 3 실행하기 /// </summary> private static void ExecuteJob3() { Console.WriteLine("JOB #3 EXECUTED"); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { Task task = Task.Run ( () => { Parallel.Invoke ( () => ExecuteJob1(), () => ExecuteJob2() ); } ); try { bool isTaskCompleted = task.Wait(10000); Console.WriteLine($"태스크 완료 여부 : {isTaskCompleted}"); Console.WriteLine($"태스크 상태 : {task.Status:G}"); } catch(OperationCanceledException exception) { Console.WriteLine(exception.ToString()); } ExecuteJob3(); Console.WriteLine("프로그램을 종료하기 위해 아무 키나 눌러 주시기 바랍니다."); Console.ReadKey(false); } #endregion } } |
TestProject.zip
■ Task 클래스의 WhenAny 정적 메소드를 사용하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Http; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// HTTP 클라이언트 /// </summary> private static HttpClient _httpClient = new HttpClient { MaxResponseContentBufferSize = 1_000_000 }; /// <summary> /// URL 리스트 /// </summary> private static List<string> _urlList = new List<string> { "https://docs.microsoft.com", "https://docs.microsoft.com/aspnet/core", "https://docs.microsoft.com/azure", "https://docs.microsoft.com/azure/devops", "https://docs.microsoft.com/dotnet", "https://docs.microsoft.com/dynamics365", "https://docs.microsoft.com/education", "https://docs.microsoft.com/enterprise-mobility-security", "https://docs.microsoft.com/gaming", "https://docs.microsoft.com/graph", "https://docs.microsoft.com/microsoft-365", "https://docs.microsoft.com/office", "https://docs.microsoft.com/powershell", "https://docs.microsoft.com/sql", "https://docs.microsoft.com/surface", "https://docs.microsoft.com/system-center", "https://docs.microsoft.com/visualstudio", "https://docs.microsoft.com/windows", "https://docs.microsoft.com/xamarin" }; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 컨텐트 길이 구하기 (비동기) - GetContentLengthAsync(httpClient, url) /// <summary> /// 컨텐트 길이 구하기 (비동기) /// </summary> /// <param name="httpClient">HTTP 클라이언트</param> /// <param name="url">URL</param> /// <returns>컨텐트 길이 태스크</returns> private static async Task<int> GetContentLengthAsync(HttpClient httpClient, string url) { HttpResponseMessage httpResponseMessage = await httpClient.GetAsync(url); byte[] contentByteArray = await httpResponseMessage.Content.ReadAsByteArrayAsync(); Console.WriteLine($"{url, -60} {contentByteArray.Length, 10:#,#}"); return contentByteArray.Length; } #endregion #region 전체 컨텐트 길이 출력하기 (비동기) - PrintTotalContentLengthAsync() /// <summary> /// 전체 컨텐트 길이 출력하기 (비동기) /// </summary> /// <returns>태스크</returns> private static async Task PrintTotalContentLengthAsync() { Stopwatch watch = Stopwatch.StartNew(); IEnumerable<Task<int>> taskEnumerable = from url in _urlList select GetContentLengthAsync(_httpClient, url); List<Task<int>> taskList = taskEnumerable.ToList(); int totalLength = 0; while(taskList.Any()) { Task<int> taskCompleted = await Task.WhenAny(taskList); taskList.Remove(taskCompleted); totalLength += await taskCompleted; } watch.Stop(); Console.WriteLine($"전체 바이트 : {totalLength:#,#}"); Console.WriteLine($"경과 시간 : {watch.Elapsed}"); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private static async Task Main() => await PrintTotalContentLengthAsync(); #endregion } } |
TestProject.zip
■ CancellationTokenSource 클래스의 CancelAfter 메소드를 사용해 타임아웃시 작업을 취소하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
using System; using System.Collections.Generic; using System.Diagnostics; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 취소 토큰 소스 /// </summary> private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); /// <summary> /// HTTP 클라이언트 /// </summary> private static HttpClient _httpClient = new HttpClient { MaxResponseContentBufferSize = 1000000L }; /// <summary> /// URL 리스트 /// </summary> private static List<string> _urlList = new List<string> { "https://docs.microsoft.com", "https://docs.microsoft.com/aspnet/core", "https://docs.microsoft.com/azure", "https://docs.microsoft.com/azure/devops", "https://docs.microsoft.com/dotnet", "https://docs.microsoft.com/dynamics365", "https://docs.microsoft.com/education", "https://docs.microsoft.com/enterprise-mobility-security", "https://docs.microsoft.com/gaming", "https://docs.microsoft.com/graph", "https://docs.microsoft.com/microsoft-365", "https://docs.microsoft.com/office", "https://docs.microsoft.com/powershell", "https://docs.microsoft.com/sql", "https://docs.microsoft.com/surface", "https://docs.microsoft.com/system-center", "https://docs.microsoft.com/visualstudio", "https://docs.microsoft.com/windows", "https://docs.microsoft.com/xamarin" }; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 컨텐트 길이 구하기 (비동기) - GetContentLengthAsync(httpClient, url, cancellationToken) /// <summary> /// 컨텐트 길이 구하기 (비동기) /// </summary> /// <param name="httpClient">HTTP 클라이언트</param> /// <param name="url">URL</param> /// <param name="cancellationToken">취소 토큰</param> /// <returns>컨텐트 길이 태스크</returns> private static async Task<int> GetContentLengthAsync(HttpClient httpClient, string url, CancellationToken cancellationToken) { HttpResponseMessage httpResponseMessage = await httpClient.GetAsync(url, cancellationToken); byte[] contentByteArray = await httpResponseMessage.Content.ReadAsByteArrayAsync(cancellationToken); Console.WriteLine($"{url, -60} {contentByteArray.Length, 10:#,#}"); return contentByteArray.Length; } #endregion #region 전체 컨텐트 길이 출력하기 (비동기) - PrintTotalContentLengthAsync() /// <summary> /// 전체 컨텐트 길이 출력하기 (비동기) /// </summary> /// <returns>태스크</returns> private static async Task PrintTotalContentLengthAsync() { Stopwatch watch = Stopwatch.StartNew(); int totalLength = 0; foreach(string url in _urlList) { int contentLength = await GetContentLengthAsync(_httpClient, url, _cancellationTokenSource.Token); totalLength += contentLength; } watch.Stop(); Console.WriteLine($"전체 바이트 : {totalLength:#,#}"); Console.WriteLine($"경과 시간 : {watch.Elapsed}"); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private static async Task Main() { Console.WriteLine("프로그램을 시작합니다."); try { _cancellationTokenSource.CancelAfter(3000); await PrintTotalContentLengthAsync(); } catch(TaskCanceledException) { Console.WriteLine("태스크가 취소되었습니다 : 타임아웃"); } finally { _cancellationTokenSource.Dispose(); } Console.WriteLine("프로그램을 종료합니다."); } #endregion } } |
TestProject.zip
■ Parallel 클래스의 Invoke 정적 메소드를 사용해 병렬 작업을 실행하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 단어 배열 구하기 - GetWordArray(url) /// <summary> /// 단어 배열 구하기 /// </summary> /// <param name="url">URL 입니다.</param> /// <returns>단어 배열</returns> private static string[] GetWordArray(string url) { Console.WriteLine($"다음 사이트에서 가져옵니다 : {url}"); string content = new WebClient().DownloadString(url); return content.Split ( new char[] { ' ', '\u000A', ',', '.', ';', ':', '-', '_', '/' }, StringSplitOptions.RemoveEmptyEntries ); } #endregion #region 가장 긴 단어 출력하기 - PrintLongestWord(wordArray) /// <summary> /// 가장 긴 단어 출력하기 /// </summary> /// <param name="wordArray">단어 배열</param> private static void PrintLongestWord(string[] wordArray) { string longestWord = ( from word in wordArray orderby word.Length descending select word ).First(); Console.WriteLine($"첫번째 작업, 가장 긴 단어 : {longestWord}"); } #endregion #region 가장 일반적인 단어 출력하기 - PrintMostCommonWord(wordArray) /// <summary> /// 가장 일반적인 단어 출력하기 /// </summary> /// <param name="wordArray">단어 배열</param> private static void PrintMostCommonWord(string[] wordArray) { IEnumerable<string> enumerable1 = from word in wordArray where word.Length > 6 group word by word into wordGroup orderby wordGroup.Count() descending select wordGroup.Key; IEnumerable<string> enumerable2 = enumerable1.Take(10); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("두번째 작업, 가장 일반적인 단어 : "); foreach(string word in enumerable2) { stringBuilder.AppendLine(" " + word); } Console.WriteLine(stringBuilder.ToString()); } #endregion #region 단어 수 출력하기 - PrintWordCount(wordArray, term) /// <summary> /// 단어 수 출력하기 /// </summary> /// <param name="wordArray">단어 배열</param> /// <param name="term">용어</param> private static void PrintWordCount(string[] wordArray, string term) { IEnumerable<string> wordEnumerable = from word in wordArray where word.ToUpper().Contains(term.ToUpper()) select word; Console.WriteLine($@"세번째 작업, ""{term}"" 단어 수 : {wordEnumerable.Count()}"); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { string[] wordArray = GetWordArray(@"http://www.gutenberg.org/files/54700/54700-0.txt"); Parallel.Invoke ( () => { Console.WriteLine("첫번째 작업을 시작합니다..."); PrintLongestWord(wordArray); }, () => { Console.WriteLine("두번째 작업을 시작합니다..."); PrintMostCommonWord(wordArray); }, () => { Console.WriteLine("세번째 작업을 시작합니다..."); PrintWordCount(wordArray, "sleep"); } ); Console.WriteLine("Parallel.Invoke 실행을 종료했습니다."); Console.WriteLine("종료하기 위해서 아무 키나 눌러주시기 바랍니다."); Console.ReadKey(false); } #endregion } } |
TestProject.zip
■ Parallel 클래스의 ForEach 정적 메소드를 사용해 합계를 구하는 방법을 보여준다. ▶ Program.cs
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 |
using System; using System.Collections.Generic; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 합계 구하기 - GetSummary(sourceEnumerable) /// <summary> /// 합계 구하기 /// </summary> /// <param name="sourceEnumerable">소스 열거 가능형</param> /// <returns>합계</returns> private static int GetSummary(IEnumerable<int> sourceEnumerable) { object mutex = new object(); int totalValue = 0; Parallel.ForEach ( source : sourceEnumerable, localInit : () => 0, body : (item, state, localValue) => localValue + item, localFinally : localValue => { lock(mutex) { totalValue += localValue; } } ); return totalValue; } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { int[] valueArray = new int[] { 10, 20, 30, 20, 10, 30, 40 , 50 }; int summrary = GetSummary(valueArray); Console.WriteLine(summrary); } #endregion } } |
TestProject.zip
■ Parallel 클래스의 ForEach 정적 메소드에서 CancellationToken 객체를 사용해 취소하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 매트릭스 값 표시하기 - DisplayMatrixValue(elementArray) /// <summary> /// 매트릭스 값 표시하기 /// </summary> /// <param name="elementArray">요소 배열</param> private static void DisplayMatrixValue(float[] elementArray) { for(int i = 0; i < elementArray.Length; i++) { float element = elementArray[i] == -0f ? 0f : elementArray[i]; Console.Write(element); if(i < elementArray.Length - 1) { Console.Write(" "); } } Console.WriteLine(); } #endregion #region 매트릭스 회전하기 - RotateMatrix(list, degree, token) /// <summary> /// 매트릭스 회전하기 /// </summary> /// <param name="list">매트릭스 리스트</param> /// <param name="degree">각도</param> /// <param name="token">취소 토큰</param> private static void RotateMatrix(List<Matrix> list, float degree, CancellationToken token) { Parallel.ForEach ( list, new ParallelOptions { CancellationToken = token }, matrix => { matrix.Rotate(degree); DisplayMatrixValue(matrix.Elements); } ); } #endregion #region 프로그램 시작하기 - Mani() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { List<Matrix> list = new List<Matrix>(); for(int i = 0; i < 10000; i++) { list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 1f)); } using CancellationTokenSource source = new CancellationTokenSource(1000); RotateMatrix(list, 30f, source.Token); } #endregion } } |
TestProject.zip
■ ParallelLoopState 클래스의 Stop 메소드를 사용해 병렬 작업을 취소하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 매트릭스 값 표시하기 - DisplayMatrixValue(elementArray) /// <summary> /// 매트릭스 값 표시하기 /// </summary> /// <param name="elementArray">요소 배열</param> private static void DisplayMatrixValue(float[] elementArray) { for(int i = 0; i < elementArray.Length; i++) { float element = elementArray[i] == -0f ? 0f : elementArray[i]; Console.Write(element); if(i < elementArray.Length - 1) { Console.Write(" "); } } Console.WriteLine(); } #endregion #region 역행렬 구하기 - InvertMatrix(list) /// <summary> /// 역행렬 구하기 /// </summary> /// <param name="list">매트릭스 리스트</param> private static void InvertMatrix(List<Matrix> list) { Parallel.ForEach ( list, (matrix, state) => { if(!matrix.IsInvertible) { Console.WriteLine("역행렬을 구할 수 없습니다."); state.Stop(); } else { matrix.Invert(); } } ); } #endregion #region 프로그램 시작하기 - Mani() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { List<Matrix> list = new List<Matrix>(); list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 1f)); InvertMatrix(list); foreach(Matrix matrix in list) { DisplayMatrixValue(matrix.Elements); } } #endregion } } |
TestProject.zip
■ Parallel 클래스의 ForEach 정적 메소드를 사용하는 방법을 보여준다. ▶ Program.cs
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 |
using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 매트릭스 값 표시하기 - DisplayMatrixValue(elementArray) /// <summary> /// 매트릭스 값 표시하기 /// </summary> /// <param name="elementArray">요소 배열</param> private static void DisplayMatrixValue(float[] elementArray) { for(int i = 0; i < elementArray.Length; i++) { float element = elementArray[i]; Console.Write(element); if(i < elementArray.Length - 1) { Console.Write(" "); } } Console.WriteLine(); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { List<Matrix> list = new List<Matrix>(); list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 0f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 0f)); list.Add(new Matrix(1f, 0f, 1f, 0f, 1f, 1f)); Parallel.ForEach(list, matrix => matrix.Rotate(30f)); foreach(Matrix matrix in list) { DisplayMatrixValue(matrix.Elements); } } #endregion } } |
TestProject.zip
■ TaskAsyncEnumerableExtensions 클래스의 WithCancellation 확장 메소드를 사용해 비동기 열거를 취소하는 방법을 보여준다. ▶ Program.cs
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 |
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 값 열거 가능형 구하기 (비동기) - GetValueEnumerableAsync(token) /// <summary> /// 값 열거 가능형 구하기 (비동기) /// </summary> /// <param name="token">취소 토큰</param> /// <returns>값 열거 가능형</returns> private static async IAsyncEnumerable<int> GetValueEnumerableAsync([EnumeratorCancellation] CancellationToken token = default) { for(int i = 0; i < 10; i++) { await Task.Delay(i * 100, token); yield return i; } } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private static async Task Main() { using CancellationTokenSource source = new CancellationTokenSource(3000); CancellationToken token = source.Token; await foreach(int value in GetValueEnumerableAsync().WithCancellation(token)) { Console.WriteLine(value); } } #endregion } } |
TestProject.zip
■ ValueTask<T> 클래스를 사용하는 방법을 보여준다. ▶ Program.cs
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 |
using System; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 값 구하기 (비동기) - GetValueAsync(source) /// <summary> /// 값 구하기 (비동기) /// </summary> /// <param name="source">소스값</param> /// <returns>값</returns> private async static ValueTask<int> GetValueAsync(int source) { await Task.Delay(source); return source; } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private async static Task Main() { int result = await GetValueAsync(3000); Console.WriteLine(result); } #endregion } } |
TestProject.zip
■ Task 클래스를 사용해 모든 태스크 종료시까지 대기하는 방법을 보여준다. ▶ Program.cs
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 75 76 77 78 79 80 81 82 83 84 |
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 값 구하기 (비동기) - GetValueAsync(source) /// <summary> /// 값 구하기 (비동기) /// </summary> /// <param name="source">소스 값</param> /// <returns>값 태스크</returns> private static async Task<int> GetValueAsync(int source) { await Task.Delay(TimeSpan.FromSeconds(source)); return source; } #endregion #region 태스크 실행하기 (비동기) - ExecuteTaskAsync(task) /// <summary> /// 태스크 실행하기 (비동기) /// </summary> /// <param name="task">태스크</param> /// <returns>태스크</returns> private static async Task ExecuteTaskAsync(Task<int> task) { int result = await task; Console.WriteLine(result); } #endregion #region 태스크 처리하기 (비동기) - ProcessTaskAsync() /// <summary> /// 태스크 처리하기 (비동기) /// </summary> /// <returns>태스크</returns> private static async Task ProcessTaskAsync() { Task<int> task1 = GetValueAsync(2); Task<int> task2 = GetValueAsync(3); Task<int> task3 = GetValueAsync(1); Task<int>[] sourceTaskArray = new[] { task1, task2, task3 }; IEnumerable<Task> taskEnumerable = from task in sourceTaskArray select ExecuteTaskAsync(task); Task[] targetTaskArray = taskEnumerable.ToArray(); await Task.WhenAll(targetTaskArray); } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> /// <returns>태스크</returns> private async static Task Main() { await ProcessTaskAsync(); } #endregion } } |
TestProject.zip
■ Task 클래스에서 반복 작업자를 사용하는 방법을 보여준다. ▶ TaskHelper.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
using System; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 태스크 헬퍼 /// </summary> public class TaskHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 실행 여부 /// </summary> private bool isRunning = false; /// <summary> /// 취소 토큰 소스 /// </summary> private CancellationTokenSource cancellationTokenSource = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 실행 여부 - IsRunning /// <summary> /// 실행 여부 /// </summary> public bool IsRunning { get { return this.isRunning; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 시작하기 - Start(workAction, workParameter) /// <summary> /// 시작하기 /// </summary> /// <param name="workAction">작업 액션</param> /// <param name="workParameter">작업 매개 변수</param> public void Start(Action<object> workAction, object workParameter) { this.isRunning = true; this.cancellationTokenSource = new CancellationTokenSource(); Task.Factory.StartNew ( () => { try { using(this.cancellationTokenSource.Token.Register(Thread.CurrentThread.Abort)) { workAction(workParameter); } } catch(ThreadAbortException) { this.isRunning = false; } }, this.cancellationTokenSource.Token ); } #endregion #region 중단하기 - Abort() /// <summary> /// 중단하기 /// </summary> public void Abort() { this.cancellationTokenSource.Cancel(); } #endregion } } |
▶ RepeatWorker.cs
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
using System; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 반복 작업자 /// </summary> public class RepeatWorker : IDisposable { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 태스크 헬퍼 /// </summary> private TaskHelper taskHelper = null; /// <summary> /// 루프 계속 여부 /// </summary> private bool continueLoop = true; /// <summary> /// 휴지 여부 /// </summary> private bool isSleep = false; /// <summary> /// 휴지 시간 /// </summary> private int sleepTime; /// <summary> /// 작업 액션 /// </summary> private Action<object> workAction; /// <summary> /// 작업 매개 변수 /// </summary> private object workParameter; /// <summary> /// 실행 여부 /// </summary> private bool isRunning = false; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 휴지 시간 - SleepTime /// <summary> /// 휴지 시간 /// </summary> public int SleepTime { get { return this.sleepTime; } set { this.sleepTime = value; } } #endregion #region 작업 액션 - WorkAction /// <summary> /// 작업 액션 /// </summary> public Action<object> WorkAction { get { return this.workAction; } set { this.workAction = value; } } #endregion #region 작업 매개 변수 - WorkParameter /// <summary> /// 작업 매개 변수 /// </summary> public object WorkParameter { get { return this.workParameter; } set { this.workParameter = value; } } #endregion #region 실행 여부 - IsRunning /// <summary> /// 실행 여부 /// </summary> public bool IsRunning { get { return this.isRunning; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - RepeatWorker() /// <summary> /// 생성자 /// </summary> public RepeatWorker() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 시작하기 - Start() /// <summary> /// 시작하기 /// </summary> public void Start() { try { if(this.isRunning) { return; } this.isRunning = true; if(this.taskHelper != null) { if(this.taskHelper.IsRunning) { this.taskHelper.Abort(); } this.taskHelper = null; } this.taskHelper = new TaskHelper(); this.taskHelper.Start(ExecuteWorkAction, null); } catch(Exception exception) { this.isRunning = false; throw exception; } } #endregion #region 중단하기 - Stop() /// <summary> /// 중단하기 /// </summary> public async void Stop() { try { if(!this.isRunning) { return; } this.isRunning = false; this.continueLoop = false; await Task.Delay(500); if(this.taskHelper != null && this.taskHelper.IsRunning) { if(this.isSleep) { this.taskHelper.Abort(); } } } catch(Exception) { } } #endregion #region 리소스 해제하기 - Dispose() /// <summary> /// 리소스 해제하기 /// </summary> public void Dispose() { Stop(); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 작업 액션 실행하기 - ExecuteWorkAction(parameter) /// <summary> /// 작업 액션 실행하기 /// </summary> /// <param name="parameter">매개 변수</param> private async void ExecuteWorkAction(object parameter) { while(this.continueLoop) { try { this.workAction?.Invoke(this.workParameter); } catch(Exception) { } if(!this.continueLoop) { break; } this.isSleep = true; await Task.Delay(this.sleepTime); this.isSleep = false; } } #endregion } } |
▶ Program.cs
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 |
using System; using System.Threading; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { RepeatWorker repeatWorker = new RepeatWorker(); repeatWorker.WorkAction = (p) => { Console.WriteLine(DateTime.Now); }; repeatWorker.WorkParameter = null; repeatWorker.SleepTime = 1000; repeatWorker.Start(); Thread.Sleep(10000); repeatWorker.Stop(); } #endregion } } |
TestProject.zip
■ Task 클래스의 CompletedTask 정적 속성/FromException 정적 메소드를 사용해 동기 실행을 비동기로 실행하는 방법을 보여준다. ▶ 예제 코드 (C#)
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 |
using System; using System.Threading; using System.Threading.Tasks; #region 실행하기 (비동기) - ExecuteAsync() /// <summary> /// 실행하기 (비동기) /// </summary> /// <returns>태스크</returns> public Task ExecuteAsync() { try { ExecuteSynchronous(); return Task.CompletedTask; } catch(Exception exception) { return Task.FromException(exception); } } #endregion #region 실행하기 (동기) - ExecuteSynchronous() /// <summary> /// 실행하기 (동기) /// </summary> private void ExecuteSynchronous() { Thread.Sleep(5000); } #endregion |
■ Task<T> 클래스의 FromException<T> 정적 메소드를 사용해 완료시 예외를 갖는 태스크를 생성하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using System; using System.Threading.Tasks; #region 실행하기 (비동기) - ExecuteAsync<T>() /// <summary> /// 실행하기 (비동기) /// </summary> /// <typeparam name="T">결과 타입</typeparam> /// <returns>결과 태스크</returns> public Task<T> ExecuteAsync<T>() { return Task.FromException<T>(new NotImplementedException()); } #endregion |
■ Task 클래스의 FromCanceled<T> 정적 메소드를 사용해 취소로 완료된 태스크를 생성하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using System.Threading; using System.Threading.Tasks; #region 값 구하기 (비동기) - GetValueAsync(cancellationToken) /// <summary> /// 값 구하기 (비동기) /// </summary> /// <param name="cancellationToken">취소 토큰</param> /// <returns>값 태스크</returns> public Task<int> GetValueAsync(CancellationToken cancellationToken) { if(cancellationToken.IsCancellationRequested) { return Task.FromCanceled<int>(cancellationToken); } return Task.FromResult(13); } #endregion |
■ Task 클래스의 CompletedTask 정적 속성을 사용해 이미 성공적으로 완료된 태스크를 구하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System.Threading.Tasks; #region 실행하기 (비동기) - ExecuteAsync() /// <summary> /// 실행하기 (비동기) /// </summary> /// <returns>태스크</returns> public Task ExecuteAsync() { return Task.CompletedTask; } #endregion |
■ Task 클래스의 FromResult<T> 정적 메소드를 사용해 성공적으로 완료된 결과를 갖는 태스크를 생성하는 방법을 보여준다. ▶ 예제 코드 (C#)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System.Threading.Tasks; #region 값 구하기 (비동기) - GetValueAsync() /// <summary> /// 값 구하기 (비동기) /// </summary> /// <returns>값 태스크</returns> public Task<int> GetValueAsync() { return Task.FromResult(10); } #endregion |