C# Asynchronous Programming Model - APM

http://msdn.microsoft.com/en-us/library/ms228963.aspx

http://msdn.microsoft.com/ko-kr/library/ms228963.aspx




APM은 BeginMethod <--> EndMethod를 쌍으로 엮여진 메소드로 비동기를 구현하는 모델이다. 이미 .Net frameworkd에서는 파일이나 네트워크 관련으로 메소드를 APM(begin, end) 방식으로 비 동기 메소드를 구현하였다. 아래 그림1에서 확인 할 수 있다.


[그림1] Begin으로 시작하는 메소드


 그림1에서와 같이 System.IO와 System.Net 하위 클래스에서 Begin으로 시작하는 메소드가 많으며 이 메소드와 쌍으로 End로 시작하는 메소드가 있을 것이다.

(해당 그림은 Object Browser에서 검색하여 나온 결과 화면이다.)



 예제로 파일을 동기와 비 동기로 저장하는 방법을 알아 보도록 하자.



동기식 파일 저장 예제

[TestMethod]
public void AsyncUnitTest_APM_Sync()
{
    var contents = "컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용 무수히 많음";
    var contentsBytes = Encoding.UTF8.GetBytes(contents);
 
    //Temp 파일 얻어 오기
    var pathInfo = Path.GetTempFileName();
    using (var fileStream = File.OpenWrite(pathInfo))
    {
        // 파일에 쓰기
        fileStream.Write(contentsBytes0, (int)contentsBytes.Length);
        fileStream.Flush();
        fileStream.Close();
    }
}


비 동기식 파일 저장 예제

[TestMethod]
public void AsyncUnitTest_APM_ASync()
{
    var contents = "컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용, 컨텐츠 내용 무수히 많음";
    var contentsBytes = Encoding.UTF8.GetBytes(contents);
 
    //Temp 파일 얻어 오기
    var pathInfo = Path.GetTempFileName();
    var fileStream = File.OpenWrite(pathInfo);
 
    // 파일에 쓰기
    var result = fileStream.BeginWrite(contentsBytes0contentsBytes.Lengthnew AsyncCallback(FileStreamReadEnd), fileStream);
    var handle = result.AsyncWaitHandle;
 
    // 완료 될 때까지 대기, 옵션 사항으로 사용함.
    WaitHandle.WaitAll(new[] { result.AsyncWaitHandle });
 
    //WaitHandle 사용으로 대기는 해당 쓰레드가 완료가 되며 아래 Flow에서 완료된 값이 필요 할 때 대기 할 수 있으나 필요치 않을 때는 대기 하지 않고 넘어 가도 됨
    #region WaitHandle에서 완료가 되면 실행 해야 하는 코드
    //code
    #endregion
}
 
public void FileStreamReadEnd(IAsyncResult result)
{
    //완료 여부 체크
    if (result.IsCompleted)
    {
        //넘겨준 파라메터를 해당 object로 변환
        var fileStream = (FileStream)result.AsyncState;
        //완료 표시
        fileStream.EndRead(result);
        fileStream.Flush();
        fileStream.Close();
    }
}

 일단 한번 Copy & Paste를 해서 디버깅 모드로 따라가면서 흐름을 익혀 보자.


동기식 실행 : 특별한 설명이 없어도 절차적으로 한번에 하나씩 순차적으로 흐름을 타고 내려가는 것을 확인 할 수 있을 것이다.

비 동기 실행 : BeginWrite를 실행하면 흐름이 두 가지로 나눠지는 것을 확인 할 수 있다.

                    BeginWrite를 실행하면 본 문맥에서는 result(IAsyncResult)객체를 반환하고 바로 아래 구문을 실행할 것이며 "WhatHandle"에서 IAsyncResult 객체가 완료가 될 때까지 대기하는 흐름이고 또 하나는 AsyncCallback에서 호출되어진 FileStreamReadEnd 메소드가 실행이 될 것이다. FileStreamReadEnd 메소드는 파일 내용을 다 읽었으면 EndRead ( 여기서는 FileStream의 BeginWrite의 쌍이다 )를 실행하여 IAsyncResult 객체에 완료가 되었다는 것을 알려 준다. 그리고 원래 하려고 하였던 Close 작업을 해 주고 완료 한다. 이와 같은 방식으로 파일 읽기를 비 동기로 작업 하였다.


 APM 타입 비동기 작업에서 중요한 객체는 IAyncResult다. 이 IAsyncResult 객체를 사용해서 비동기 진행 상태나 완료 상태를 알아 내고 Begin 할때 넘겨준 파라메터 객체를 이용해 특정 객체를 접근할 수 있다. 아래 그림1은 IAsyncResult의 전체적인 flow이다.


[그림1] IAsyncReslt 흐름도


 BeginMethod를 실행하면 IAsyncResult 돌려줘서 현재 문맥에서 컨트롤 할 수 있도로 하며(대기 또는 진행 여부 체크 등) AsyncCallbacak에서 정의해준 EndMethod를 실행할 때 파라메터로 IAsyncResult를 넘겨 준다. BeginMethod에서 반환된 IAsyncResult 객체와 EndMethod에서 받은 IAsyncResult 파라메터는 각은 객체다. 


 IAsyncResult 객체의 흐름과 BeginMethod, EndMethod의 상관관계를 알고 있으면 쉽게 비동기 실행할 수 있을 것이다. 아래는 IAsyncResult 객체의 맴버에 대한 설명이다. (MSDN 발췌)


멤버

설명

AsyncState

비동기 작업에 대한 정보를 포함하는 선택적 응용 프로그램 관련 개체입니다.

AsyncWaitHandle

비동기 작업이 완료될 때까지 응용 프로그램 실행을 블로킹하는 데 사용할 수 있는 WaitHandle입니다.

CompletedSynchronously

비동기 작업이 별도의 ThreadPool 스레드에서 완료되는 대신 BeginOperationName 호출에 사용된 스레드에서 완료되었는지 여부를 나타내는 값입니다.

IsCompleted

비동기 작업이 완료되었는지 여부를 나타내는 값입니다.


+ Recent posts