C# Event-based Asynchronous Pattern - EAP (1)

이벤트 기반 비동기 프로그래밍 패턴


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


 이벤트 기반 비동기 패턴은 APM에서 문제(dead lock, cancellation)가 될 수 있는 사항을 피할 수 있습니다. 이 패턴을 지원하는 가이드로 개발하면 다음 작업을 수월히 수행할 수 있습니다. ( - 이벤트 기반 비동기 프로그래밍은 UI가 있는 어플리케이션에서 주로 사용한다. 라이브러리가 제공되는 Async 메소드를 실행하면 Completed나 Changed 이벤트를 받아서 후속 작업을 처리하면 된다. WinForm이나 WPF에서 많이 사용 한다. - EAP를 사용 해야 할 때 - )

  • 다운로드와 데이터베이스 작업 등 시간이 많이 걸리는 작업을 중단하지 않고 "백그라운드에서" 수행

  • 여러 작업을 동시에 실행하며 각 작업이 완료될 때 알림을 받음

  • 응용 프로그램을 중지하지 않고 리소스를 사용할 수 있을 때까지 대기

  • 익숙한 이벤트 및 대리자 모델을 사용하여 보류 중인 비동기 작업과 통신

 이벤트 기반 비동기 패턴은 MethodAsync, MethodCompleted, MethodCancel로 제공되며 이 메소드로 각 작업을 수행하며 위 사항을 지원 한다. 우선 예제를 통해 눈으로 확인을 해봐야 대략적으로 알 수 있을 것이다. 아래 예제를 보도록 하자.

BackgroundWorker bw = new BackgroundWorker();
//RunWorkerAsync() 메소드가 실행되 면 비동기로 실행 될 코드
bw.DoWork += bw_DoWork;
//완료시 처리할 이벤트 핸들로
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
//상태가 변경되면  처리할 이벤트 핸들로
//통상적으로 진행율을 표시하는 걸로 사용 한다.
bw.ProgressChanged += bw_ProgressChanged;
 
//비동기로 메소드 실행
bw.RunWorkerAsync();
            
//비동기 작업을 취소 할 때 사용 한다.
//bw.CancelAsync();

[코드 1] 비동 메소드 사용 예제


 BackgroundWorker 클래스는 일반적인 사항에서 비동기적으로 처리할 일을 대신 맡아서 처리하는 클래스다 일반적인 케이스에서는 이 클래스를 사용해서 비 동기 작업을 진행하면 무리가 없을 것이다. 이 클래스는 Winform, ASP.NET, WPF에서 효과적으로 동작 한다.


EAP를 제공하는 라이브러리를 위와 같이 사용하며 전체 소스는 아래와 같다.

/// <summary> /// 진행율 표시 /// </summary> private int inc; /// <summary> /// 이벤트 기반 비동기 테스트 /// </summary> [TestMethod] public void BackgroundWorker_EAP_ASync() {     BackgroundWorker bw = new BackgroundWorker();     //RunWorkerAsync() 메소드가 실행되 면 비동기로 실행 될 코드     bw.DoWork += bw_DoWork;     //완료시 처리할 이벤트 핸들로     bw.RunWorkerCompleted += bw_RunWorkerCompleted;     //상태가 변경되면  처리할 이벤트 핸들로     //통상적으로 진행율을 표시하는 걸로 사용 한다.     bw.ProgressChanged += bw_ProgressChanged; //진행상황을 보고 하도록 서정 함(ProgressChanged 이벤트가 동작 한다)     bw.WorkerReportsProgress = true;

    //비동기로 메소드 실행     bw.RunWorkerAsync();     do

    {         //비동기가 끝날때까지 대기         if (bw.IsBusy)         {             Thread.Sleep(1000);         }         else         {

//비동기 작업이 종료되면 loop 밖으로 나간다.             break;         }     } while (true);

    //비동기 작업을 취소 할 때 사용 한다.     //bw.CancelAsync();     Assert.AreEqual(inc100); } /// <summary> /// 백그라운드의 상태가 변경되었을 때 상태값을 파라메터로 넘겨 받아 처리 한다. /// </summary> /// <param name="sender">BackgroundWorker</param> /// <param name="e">ProgressChangedEventArgs</param> void bw_ProgressChanged(object senderProgressChangedEventArgs e) {     int progress = e.ProgressPercentage;     //진행율을 표기 한다. } /// <summary> /// 비동기로 실제 작업을 수행하는 코드 /// </summary> /// <param name="sender">BackgroundWorker</param> /// <param name="e">DoWorkEventArgs</param> void bw_DoWork(object senderDoWorkEventArgs e) {     inc = 0;     BackgroundWorker worker = (BackgroundWorker)sender;     do     {         //취소 여부를 체크         if (worker.CancellationPending)         {             e.Cancel = true;    //취소로 상태 변경             break;  //loop out         }         else         {             inc++;             worker.ReportProgress(inc);         }         Thread.Sleep(100);     } while (!e.Cancel && inc < 100); //취소 신호가 있으면 바로 나간다, 완료되면 out } /// <summary> /// 비 동기 작업수행이 완료가 되면 실행 된다. /// </summary> /// <param name="sender">BackgroundWorker</param> /// <param name="e">RunWorkerCompletedEventArgs</param> void bw_RunWorkerCompleted(object senderRunWorkerCompletedEventArgs e) {     if (e.Cancelled)     {         //취소 메세지를 처리 한다.         Console.WriteLine("취소 됨");     }     else     {         //완료에 해당하는 작업을 수행한다.         Console.WriteLine("정상적으로 완료");     } }


 EAP 방식은 위에 나타난 소스 말고도 이벤트 핸들러에 필수 적인 EventsArgs를 상속받은 객체를 세가지 더 구현해야 하는 불편함이 있다. 라이브러리를 사용하는 프로그래머는 어렵지 않게 제공되는 형식의 이벤트대로 구현을 하면 되지만 라이브러리를 만드는 프로그래머는 신경을 써야 하는 부분도 많다. 그렇지만 추상적인 흐름을 만들어 두어 그 안에서 비동기를 지원하도록 하기 때문에 사용자가 쉽게 접근하여 비동기 프로그래밍을 할 수 있도록 강제 또는 가이드를 할 수 있는 이점이 있다. 


 위 케이스는 하나의 객체에서 여러번의 일을 비동기로 수행할 수 있는 방안은 아니며 "userState" 객체를 이용해서 여러번 수행 할 수 있도록 구분할 수 있는 매커니즘을 구현해야 한다.


 다음 포스트에서는 EAP 라이브러리를 만드는 작업에 대해서 알아 보도록 하겠다.

C# Asynchronous Programming Patterns

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

 

 요즘은 앱 전성 시대인거 같다. iOS를 기점으로 시작한 앱 개발 경쟁이 안드로이드와 Windows Phone으로 까지 번기게 되며 이제는 기존 어플리케이션도 앱과 같은 형식으로 배포를 하려하는 움직임까지 보이고 있다. 더군다나 이제는 MS Office 제품군에서도 내부 확장을 앱 형식으로 확장해서 사용할 수 있도록 지원해주고 있다. 예로 Outlook 2013에서 사용할 수 있는 앱을 개발하면 C/S와 Web에서 같은 앱을 사용할 수 있도록 지원해 주고 있다.

 

 이와 같이 앱 개발 전성시대와 함께 중요하게 대두된 것이 사용자 경험에서 중요한 변화가 시작이 되었다. 끊김없는 UI, 미려한 화면, 즉각적인 반응 등이 EndUser에게 선택되는 중요한 요점이 되었다. 프로그래머 입장에서는 비동기 프로그램 방식으로 위와 같은 형식으로 개발하여 사용자 경험에 대해 지원 해 줄 수 있다.

 

 .Net에서는 Async 개발 지원을 "Asynchronous Programming Pattern"을 통해 가이드를 해 주고 있다. 아래 리스트는 MS에서 가이드 해주는 패턴이다.

- Asynchronous Programming Model (APM)

Event-based Asynchronous Pattern (EAP)

- Task-based Asynchronous Pattern (TAP)

 (http://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2287)

 

아래는 간단하게 패턴 유형 별 코드를 비교해 보도록 하겠다.

 

Sync Pattern

public class MyClassAsync
{
    public int Read(byte[] bufferint offsetint count);
}

 

APM

public class MyClassAPM
{
    public IAsyncResult BeginRead(
        byte[] bufferint offsetint count,
        AsyncCallback callbackobject state);
    public int EndRead(IAsyncResult asyncResult);
}

 

EAP

public class MyClassEAP
{
    public void ReadAsync(byte[] bufferint offsetint count);
    public event ReadCompletedEventHandler ReadCompleted;
}

 

TAP - 추천 하는 방법 ( .Net framework 4.0 이상 지원 )

public class MyClassTAP
{
    public Task<int> ReadAsync(byte[] bufferint offsetint count);
}

 

여기에 추가적으로 .Net Framwork 에서는 async / await 패턴이 추가 되었다.

public class MyClassAsyncAWait {     public async ReadAsync(byte[] bufferint offsetint count);  }

 

 이와 같이 .Net framework 에서는 비동기 프로그래밍에 대해서 보다 쉽고, 개발자의 수고를 덜 수 있도록 점점 진화된 비동기 프로그래밍 개발을 지원해 주고 있다.

 

다음 포스트 각 패턴에 따르는 예제 코드를 하나 하나씩 짚어 보도록 하겠다.

+ Recent posts