1. 스레드를 이용한 비동기 처리
1 2 3 4 5 6 7 8 9 10 11 12 | private void Button_Click(object sender, RoutedEventArgs e) { label.Content = " "; var th = new Thread(DoSomething); th.Start(); } private void DoSomething() { DoLongTimeWork(); Dispatcher.BeginInvoke((Action)delegate() { label.Content = "종료"; }); } | cs |
Thread 클래스의 생성자로 비동기로 실행할 메서드를 지정한 후 스레드를 Start 시켜준다.
폼 위에 있는 컨트롤은 UI스레드가 아니면 받아들이지 않으므로 BeginInvoke 메서드로 UI 스레드 상에서 실행시킴.
2. BackgroudWorker를 사용한 비동기 처리
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 | private BackgroundWorker _worker = new BackgroundWorker(); public MainWindow() { InitializeComponent(); _worker.DoWork += _worker_DoWork; _worker.RunWorkerCompleted += _worker_RunWorkerCompleted; _worker.ProgressChanged += _worker_ProgressChanged; _worker.WorkerReportsProgress = true; } private void _worker_DoWork(object sender, DoWorkEventArgs e) { var collection = Enumerable.Range(1, 200).ToArray(); int count = 0; foreach (var n in collection) { var per = count * 100 / collection.Length; _worker.ReportProgress(per, null); count++; Thread.Sleep(100); } } private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { progressBar.Value = progressBar.Maximum; label.Content = "종료"; } private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar.Value = e.ProgressPercentage; } private void Button_Click(object sender, RoutedEventArgs e) { label.Content = " "; _worker.RunWorkerAsync(); } | cs |
이벤트를 사용해 비동기 처리를 구현할 수 있음.
RunWorkerAsync() 메서드가 호출되면 DoWork에 등록된 이벤트가 비동기로 실행된다.
3. Task를 이용한 비동기 처리
1 2 3 4 5 | private void Button_Click(object sender, RoutedEventArgs e) { label.Content = " "; Task.Run(() => DoSomething()); } | cs |
4. async await을 이용한 비동기 프로그래밍
1 2 3 4 5 6 | private async void Button2_Click(object sender, RoutedEventArgs e) { label.Content = " "; await Task.Run(() => DoSomething()); label.Content = "종료"; } | cs |
async로 수식된 메서드는 비동기 메서드가 되어 이 안에서만 await을 사용할 수 있다.
await 키워드는 지정한 Task가 끝날 때까지 처리를 중단하고 지정한 Task가 끝나면 이후의 처리를 계속함.
5. 비동기 메서드를 정의
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private async Task<long> DoSomethingAsync(int milliseconds) { var sw = Stopwatch.StartNew(); await Task.Run(() => DoLongTimeWork()); sw.Stop(); return sw.ElapsedMilliseconds; } private async void Button2_Click(object sender, RoutedEventArgs e) { label.Content = " "; var elapsed = await DoSomethingAsync(4000); label.Content = $"{elapsed}초"; } | cs |
DoSomething 메서드 자체를 비동기로 만들 수도 있다.
리턴값이 없다면 반환형을 Task. 있다면 Task<Result>형으로 지정해야한다.
task를 리턴하므로 버튼클릭에서는 그대로 await 메서드로 사용하면 된다.
6. PLINQ를 통한 병렬 처리
Parallel LINq(PLINQ)를 사용하면 LINQ의 쿼리 처리를 쉽게 병렬화할 수 있음.
1 2 3 4 5 | var selected = books.AsParallel() .WithDegreeOfParallelism(16) .AsOrdered() .Where(b => b.Price > 500 && b.Pages > 400) .Select(b => new { b.Title }); | cs |
AsParallel 메서드로 병렬화 할 수 있지만 순서를 보장할 수 없으므로
AsOrdered 메서드를 호출하면 순서를 보장할 수 있다. 다만 성능은 떨어짐.
- 병렬화할 하나하나의 처리에 시간이 오래 걸리거나
- 데이터 소스의 양이 많을 경우
에만 병렬화를 하자.
WithDegreeOfParallelism 메서드는 동시 실행되는 태스크 수를 제한 할 수 있다.
코어가 24개 있다면 16개만 사용하고 8개는 다른 작업을 위해 남겨둘 수 있음.
7. Task를 이용한 병렬 처리
1 2 3 4 | var task1 = Task.Run(() => GetPrimeAt5000()); var task2 = Task.Run(() => GetPrimeAt6000()); var prime1 = await task1; var prime2 = await task2; | cs |
그냥 2개의 메서드를 병렬로 호출하고 끝날때까지 기다린다.
1 2 | var task1 = await Task.Run(() => GetPrimeAt5000()); var task2 = await Task.Run(() => GetPrimeAt6000()); | cs |
이런식으로 호출하면 병렬 처리가 되지않고 하나씩 처리되므로 주의해야한다.
1 2 3 4 5 6 7 | var tasks = new Task<int>[] { Task.Run(() => GetPrimeAt5000()), Task.Run(() => GetPrimeAt6000()), }; var results = await Task.WhenAll(tasks); | cs |
병렬하는 개수가 많다면 Task.WhenAll을 사용하여 각 반환값을 배열 형태로 받을 수 있다.
'프로그래밍 공부 > C#' 카테고리의 다른 글
템플릿 메서드 패턴 / 전략 패턴 (0) | 2019.02.21 |
---|---|
프로세스, 버전, 구성파일(config), Http통신, zip파일처리, 협정세계시(utc) (0) | 2019.01.28 |
Entity Framework 사용하기 (0) | 2019.01.28 |
직렬화, 역직렬화 (0) | 2019.01.24 |
XML 파일 처리 (0) | 2019.01.24 |