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 라이브러리를 만드는 작업에 대해서 알아 보도록 하겠다.

+ Recent posts