본문 바로가기

진리는어디에/C#

[C#] 비동기 프로그래밍 - async io

동기와 비동기의 차이

이전 포스트 [C#] 비동기 프로그래밍 - async/await에서는 연산 중심의 비동기 메소드를 작성하는 방법에 대해 살펴 보았다. 이번 포스트에서는 IO 중심의 비동기 예를 살펴 보도록하겠다.

먼저 동기 IO가 어떻게 이루어지는 아래 그림을 통해 살펴 보자. 예를 들어 FileStream 객체의 Write메소드를 이용해 파일에 무엇인가 쓰려고하면 아래 그림과 같은 과정이 진행 된다.

동기(sync) IO

실제 쓰기 작업은 프로그램이나 OS 영역이 아닌 하드웨어 영역에서 이루어지는데 동기 IO, 그러니까, 블로킹 호출에서는 쓰기 작업이 완료 될 때까지 프로그램이 대기하게 된다.

비동기는 IO를 요청하고 대기하는 것이 아니라 즉시 리턴 한다. 그리고 IO작업이 완료 되면 OS를 통해 그 완료를 통보 받아 나머지 작업을 CLR 스레드 풀에서 계속 진행 할 수 있다.

비동기(async) IO

 

Example

아래 예제는 동기 IO(SyncWrite)와 비동기 IO(AsyncWrite)의 사용 예를 보여주고 있다. async/await에 대한 내용은 이전 포스트에서 충분히 다루었으므로 여기서는 단순히 사용 예만 보이도록 하겠다.

using System;
using System.IO;

class Program
{
    public void SyncWrite()
    {
        using (FileStream fs = new FileStream("a.txt", FileMode.Create))
        {
            Console.WriteLine("SyncWrite Start");
            byte[] buff = new byte[1024 * 1024 * 1000];
            fs.Write(buff);
            Console.WriteLine("SyncWrite Finish");
        }
    }
    public async void AsyncWrite()
    {
        using (FileStream fs = new FileStream("a.txt", FileMode.Create))
        {
            Console.WriteLine("AsyncWrite Start");
            byte[] buff = new byte[1024 * 1024 * 1000];
            await fs.WriteAsync(buff); // 완료 되면 OS가 나머지를 실행 해줌
            Console.WriteLine("AsyncWrite Finish");
        }
    }
    public static void Main()
    {
        var program = new Program();
        program.SyncWrite();
        program.AsyncWrite();

        Console.WriteLine("Main");
        Console.ReadLine();
    }
}

// OUTPUT :
//  SyncWrite Start
//  SyncWrite Finish
//  AsyncWrite Start
//  Main
//  AsyncWrite Finish

프로그램의 실행 결과를 살펴 보면 AsyncWrite는 쓰기 작업 이후 바로 리턴하여 메인 메소드를 계속 진행 했음을 알 수 있다. 그리고 쓰기가 완료 되었을 때 await 이후 부분을 내부 스레드 풀에서 실행하여 Finish 메세지가 출력 된것을 볼 수 있다.

마치며

연산 위주의 비동기 프로그래밍은 cpu를 지속적으로 사용하고 무엇인가를 바쁘게 계속 하고 있으므로 스레드를 할당하여 연산을 계속 할 수있도록 만들어 주는 반면, IO 위주 비동기 작업은 IO작업 요청이 후 대기 외에는 딱히 하는 것이 없으므로 스레드를 따로 배분하지 않는다. 다만 IO 작업이 완료 되고 난 후, OS에서 어플리케이션으로 IO가 완료 되었음을 알려주고 난뒤에 처리해야 될 작업들은 CLR 스레드 풀에서 돌아간다는 차이가 있다.

부록 1. 같이 읽으면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!