ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C# 비동기 프로그래밍(async/await)
    개발/C# 2026. 1. 14. 12:07
    반응형

    C# 개발자라면 언젠가 반드시 마주치게 되는  async와 await 이야기를 해보려 합니다.

    열심히 코드를 짰는데 버튼을 누르는 순간 프로그램이 굳어버리거나(프리징), 데이터 불러오는 동안 아무것도 못 했던 경험 다들 있으시죠? 저도 처음엔 "그냥 순서대로 실행되면 좋은 거 아닌가?" 했다가 비동기의 세계를 맛보고 신세계를 경험했거든요.

     

     

     

    1. 비동기가 도대체 왜 필요한가요? (커피숍 비유)

    이걸 이해하려면 커피숍을 생각하면 편합니다.

    • 동기(Synchronous): 직원이 주문을 받고 커피가 나올 때까지 손님을 앞에 세워둡니다. 다음 손님은 커피가 나올 때까지 주문도 못 하고 기다려야 하죠. (UI가 멈추는 이유!)
    • 비동기(Asynchronous): 직원이 주문을 받고 '진동벨'을 준 뒤, 바로 다음 손님 주문을 받습니다. 커피가 다 되면 벨이 울리고 그때 손님이 커피를 받으러 오죠. (UI가 살아있는 이유!)

     

    2. 코드

    [안 좋은 예: "나 일 끝날 때까지 기다려!"] 아래처럼 짜면 파일을 다 읽을 때까지 프로그램 전체가 멈춥니다.

    public void DownloadData()
    {
        // 여기서 5초가 걸린다면? 그동안 프로그램은 '응답 없음'이 뜹니다.
        Thread.Sleep(5000); 
        Console.WriteLine("다운로드 완료!");
    }

     

     

    [좋은 예: "나 일하는 동안 딴거 하고 있어!"] async와 await를 쓰면 벨을 주는 것처럼 동작합니다.

     

    public async Task DownloadDataAsync()
    {
        // 비동기로 5초를 기다립니다. 그동안 UI는 멈추지 않고 계속 작동합니다.
        await Task.Delay(5000); 
        Console.WriteLine("비동기 다운로드 완료!");
    }

     

     

    3. 응용

    ["하나씩 순서대로 기다리기"]

    // 프로필 가져오는 데 2초, 게시물 가져오는 데 2초 걸린다고 가정하면
    var profile = await GetProfileAsync(); // 2초 대기
    var posts = await GetPostsAsync();     // 2초 대기
    // 총 4초 소요... (생각보다 느리죠?)

    이건 진동벨을 받았는데, 커피 나올 때까지 가만히 서 있다가 커피가 나오면 그제야 "아 맞다, 케이크도 주세요"라고 주문하는 것과 같습니다. 비효율적

     

     

    [ "한꺼번에 주문하고 떼창 기다리기"]

    이럴 땐 Task.WhenAll을 쓰면 훨씬 빨라집니다. 일단 주문(실행)을 다 던져놓고, 다 끝날 때까지 한 번만 기다리는 방식이에요.

    // 일단 작업을 시작(주문)합니다. await를 바로 붙이지 않는 게 포인트!
    var profileTask = GetProfileAsync(); 
    var postsTask = GetPostsAsync();
    
    // 두 작업이 다 끝날 때까지 '동시에' 기다립니다.
    await Task.WhenAll(profileTask, postsTask);
    
    // 결과 꺼내기
    var profile = await profileTask;
    var posts = await postsTask;
    // 총 2초 소요! (제일 오래 걸리는 작업 시간만큼만 걸립니다.)

     

     

    4. 가장 많이 하는 실수 3가지

    저도 처음에 많이 했던 실수들인데, 이것만 알아두셔도 "오, 코딩 좀 하네?" 소리 들으실 거예요.

    ① async void는 웬만하면 쓰지 마세요 이벤트 핸들러(버튼 클릭 등)가 아니라면 항상 async Task를 쓰세요. void로 쓰면 에러가 났을 때 프로그램이 그냥 꺼져버릴 수 있고 추적도 안 됩니다.

    ② Task.Wait()나 .Result는 독약입니다 비동기 함수를 호출하면서 "빨리 결과 내놔!" 하고 기다리게 만드는 코드인데, 이거 쓰면 **데드락(Deadlock)**이라고 해서 프로그램이 영원히 멈춰버릴 수 있습니다. 기다릴 땐 무조건 await를 쓰세요.

    ③ '벨'을 줬으면 '확인'도 해야 합니다 await를 빼먹으면 비동기 함수는 실행되지만, 그 결과를 기다리지 않고 다음 줄로 넘어가 버립니다. 요리가 안 나왔는데 손님이 가버리는 셈이죠.

     

     

     

     

     

    처음엔 Task, Task<T>, await 이런 단어들이 낯설고 헷갈리실 거예요. 하지만 딱 하나만 기억하세요. "시간이 오래 걸리는 일은 비동기로 던져두고, 결과가 올 때까지 기다려준다(await)!"

    이것만 익숙해져도 여러분의 프로그램은 훨씬 더 부드럽고 전문적으로 보일 겁니다. 

     

     

     

    실제로 저도 외부 API 3~4개를 연동해야 하는 작업에서 이 방식을 썼더니 응답 속도가 많이 줄어드는 걸 경험했어요. 여러분의 프로젝트에서도 await를 남발하고 있지는 않은지 한 번 점검해 보시면 좋을 것 같습니다!

     

     

     

     

    반응형
Designed by Tistory.