2022.04.23
공부를 하게 된 이유가 무지 단순하다. 프로그래밍을 하다가 자꾸 Await 이라는 함수가 나오고 자꾸 함수 앞에 Async가 붙었고 심지어 For문을 작성하다가도 자동완성에 await이 쳐지면서 자꾸 Async가 나오길래 저게 뭔데 자꾸 나오나 싶었고 이번 프로젝트에서 로딩 화면을 만드는 곳에서도 LoadAsync 라는 것이 있길래 공부 하게 되었다.
먼저 비동기 동기를 알아볼 필요가 있다. 먼저 예를 들어 MicroSorft Docs에도 나온 것 처럼 동기(Synchronism) 말 그대로 동시성을 가지는 말 이다. Docs에 나와있는대로 토스트를 만드는 것을 예로 들어보자.
이렇게 동작을 수행하는 토스트 만들기 단계를 나타내 보았다.

빵을 굽고 프라이펜을 데우고 계란을 굽는것과 같이 전단계가 완료되면 다음을 순차적으로 실행한다. 이것이 동기(Synchronism)의 개념이다. 그리고 동기는 동시에 일어난다는 말 과 같이 요청한 그 자리에서 결과를 얻는다 순차적으로 실행하여 순서가 보장된다.

이렇게 빵을 구우면서 프라이팬에 불을 올려 데우고 데워지면서 계란을 굽고 나서 거의 다 구웠을쯤에 한켠에 햄을 굽기를 하면 이렇게 작업시간도 단축이 된다. 다음은 비동기(Asynchronous) 동시에 일어나지 않는다는 말 이다. 우리가 처음에 본 그림과 같이 먼저 앞에 일을 처리 하고 그 다음 일을 처리하기 시작한다.
동기보다 복잡하지만 결과가 주어지는데 시간이 걸려도 다른 작업이 가능해 자원을 효율적으로 사용이 가능하다. 그래서 동기는 매우 직관적이고 간단하게 설계가 되어있지만 결과가 주어질 때까지 아무것도 못하고 대기해야하는 단점이 있다.
동기식 토스트기 코드 ( 예제 : MicroSorft Docs )
using System;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Toast{}
class Juice{}
class Bacon{}
class Egg{}
class Coffee{}
class Program
{
static void Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Egg eggs = FryEggs(2);
Console.WriteLine("eggs are ready");
Bacon bacon = FryBacon(3);
Console.WriteLine("bacon is ready");
Toast toast = ToastBread(2);
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}
private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");
private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");
private static Toast ToastBread(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
Task.Delay(3000).Wait();
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
private static Bacon FryBacon(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
Task.Delay(3000).Wait();
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
Task.Delay(3000).Wait();
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static Egg FryEggs(int howMany)
{
Console.WriteLine("Warming the egg pan...");
Task.Delay(3000).Wait();
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
Task.Delay(3000).Wait();
Console.WriteLine("Put eggs on plate");
return new Egg();
}
private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
}
}
다 볼 필요 없고 Main에 집중하면 된다. 동기적으로 실행했을때 순차적으로 실행된다. 즉, 하나가 끝나야 그 다음이 있다. 이것이 동기식 프로그래밍 구조이다. Wait이 블로킹 하여 순차적으로 실행이 된다.
비동기식 토스트기 코드 ( 예제 : https://kangworld.tistory.com/25 )
static async Task Main(string[] args)
{
Task.Delay(5000).Wait();
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);
var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
if (finishedTask == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("toast is ready");
}
breakfastTasks.Remove(finishedTask);
}
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
작업 Task를 List에 추가 하여 더욱 빠른속도로 토스트를 구워낼수 있게 되었다. Await이 추가되어 함수앞에 Async가 붙게 된것이 변경된 내용이다. Version 2와 다르게 임의의 Task를 고정적으로 기다릴 필요 없이 완료된 시간에 따라 Task의 처리가 이루어진다.
'C#' 카테고리의 다른 글
| C# - Func 과 Action (0) | 2021.12.21 |
|---|---|
| C# Interface (인터페이스 구현) (0) | 2021.11.29 |
| C# Property(프로퍼티) 와 Delegate(델리게이트) (0) | 2021.11.24 |
| Class와 List 활용하여 쉽게 객체 관리하기 (2) | 2021.10.25 |