상세 컨텐츠

본문 제목

C# 공부 - 기타 비동기 프로그래밍

C#

by go_ra_ni 2024. 2. 4. 21:48

본문

728x90

모든언어에서 중요한 부분인 멀티 쓰레드, 비동기 프로그래밍에 대해 약간 고찰해보는 시간을 가진다.

 

 

개념

 

1. 비동기 프로그래밍

 

보통 코드는 순차적으로 실행된다. 

하지만 여러가지 작업을 동시에 수행하고 싶을 때 비동기 프로그래밍을 사용한다.

 

예를 들어 UI에서 버튼을 클릭하면 덧셈 연산을 1만번하는 프로그래밍이 있다고 하자.

동기 프로그래밍이라면 1만번 연산 할 동안 화면은 정지된다.

 

비동기 프로그래밍은 버튼을 누르면 연산을 담당하는 담당자 쓰레드가 해당 작업을 진행하고

(멀티쓰레드 비동기일 때 기준! / 싱글 쓰레드 비동기의 경우 (자바스크립트) 작업을 돌아가면서 진행하거나 외부로 넘기거나 한다..)

메인 쓰레드는 UI 반응을 감지하며 화면이 정지되지 않게 한다.

 

2. 멀티쓰레딩

일꾼이라고 생각하면 된다.

기본은 메인쓰레드로 일꾼이 1명이여서 혼자서 여러가지 일을 동시에 할 수 없다.

멀티쓰레딩 작업을 진행하면 일꾼 자체가 늘어나서 여러가지 일을 맡길 수 있다.

 

 

 

핵심 키워드

async

설명서: https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/asyn

 

async - C# 참조 - C#

async - C# 참조

learn.microsoft.com

async 키워드를 메서드, 람다 식, 무명 메서드에 붙이면 비동기 메서드로 지정할 수 있다.

메소드 내에 await 키워드를 포함시켜야 한다.!!

(포함시키지 않아도 돌아가긴하는데 경고가 발생한다.)

no await

 

반환 값:

많이 놓칠 수 있는 부분이라고 생각한다.

async를 붙이면 끝이 아니고 추가로 반환 타입을 정해줘야 하는데

 

Task

Task<TResult>

void

타입으로 반환이 가능하다.

또한 in, ref, out의 사용이 불가능 하다.

 

그냥 Task만 반환하는 경우가 void라고 생각하면될 것 같고

반환 타입이 필요하다면 Task<TResult>형식으로 사용한다.

 

void는 주로 이벤트 핸들러에서 사용한다고 한다. 다만 해당 메소드에 대해 await가 불가능하고 예외 포착이 불가능하다.

await

비동기 프로그램의 시작부분이다.

 

먼저 이 코드를 돌려보자

 

static async Task CheckAsync() 
{
    Console.WriteLine("1메인! 현재 쓰레드 번호 :{0}", Thread.CurrentThread.ManagedThreadId);
    Run();
    Console.WriteLine("2메인! 현재 쓰레드 번호 :{0}", Thread.CurrentThread.ManagedThreadId);
}

private static async Task Run() 
{
    Console.WriteLine("함수 내부! 현재 쓰레드 번호 :{0}",Thread.CurrentThread.ManagedThreadId);
    sum = await NewTask(3);
    Console.WriteLine("await 이후! 현재 쓰레드 번호 :{0} sum : {1}", Thread.CurrentThread.ManagedThreadId, sum);
}
       
private static async Task<int> NewTask(int num)
{
    int temp = 0;
    for (int i = 0; i < 2; i++)
    {
        temp += i;
        Thread.Sleep(1000);
    }
    Console.WriteLine("await로 실행된 함수! 현재 쓰레드 번호 :{0}", Thread.CurrentThread.ManagedThreadId);
    return num;
}

 

결과

 

async와 await를 사용했지만 메인쓰레드가 계속 작업을 진행했다.

핵심 부분은 await NewTask(3); 인데 함수를 await하니 그냥 동기프로그램으로 진행되었다.

당연하다!

await 키워드는 기다린다는 의미로 비동기 프로그램에서 코드 순서를 순차적으로 진행하기 위해 사용하는 키워드이다!

해당 코드는 비동기 키워드를 많이 사용했지만 동기프로그램처럼 동작하고 있다.

 

그렇다면 위 코드에서 NewTask를 비동기로 실행하고 싶다면 어떻게 해야할까?

 

 

task

 

private static async Task Run() 
{
    Console.WriteLine("함수 내부! 현재 쓰레드 번호 :{0}",Thread.CurrentThread.ManagedThreadId);
    Task.Run(() => { NewTask(3); });
    Console.WriteLine("await 이후! 현재 쓰레드 번호 :{0} sum : {1}", Thread.CurrentThread.ManagedThreadId, sum);
}

Run 메서드를 조금 변경하였다.

Task.Run을 사용하여 새로운 Task를 실행시켰고 그 결과

 

비동기 결과

 

비동기 함수 NewTask가 실행되는 동안 메인쓰레드가 할 일을 전부 마무리했고 그 뒤에 NewTask가 마무리되는 모습이다.

 

중요한 점은 async, await가 있다고 해서 무조건 비동기가 아니라는 점이다!

 

또한 비동기 사용 시 await를 사용하지 않는다면 메소드 종료 시점 관리가 불가능하기 때문에 매우 위험하다.

 

이런 코드를 실행시켜보자

 

static void Main(string[] args)
{
    Task taskA = new Task(() => Console.WriteLine("Hello from taskA."));
    taskA.Start();
    for (int i = 0; i < 80; i++)
    {
        Console.WriteLine("Hello from thread '{0}'.",
                      Thread.CurrentThread.Name);
    }
    Console.ReadLine();
}

메소드 관리 불가능

어느 시점에 Task가 실행될지 알 수 없게 된다...

 

 

정리하자면

 

async : 비동기 메서드 선언 키워드

 

await : 비동기 메서드가 실행될 때까지 대기한다.

 

task :  비동기 작업 그 자체

 

Task.Run(Action)

Task t = new Task(Func);

Task.Start();

처럼 사용이 가능하고 비동기로 실행된다.

 

 

 

728x90

'C#' 카테고리의 다른 글

C# 공부 5일차  (0) 2024.01.17
C# 공부 4일차  (1) 2024.01.11
C# 공부 3일차  (1) 2024.01.04
C# 공부 2일차  (2) 2024.01.04
C# 공부 1일차  (3) 2024.01.03

관련글 더보기