Asynchronous Programming in .NET

written by Bipin Joshi
translated by Asptomorrow
소 개

  .NET 프레임워크 에서 비동기 프로그래밍의 지원은 잘 구현되어 있다. 비동기 프로그래밍 모델은 전체 성능을 향상시킬 뿐만아니라 응용프로그램들을 더욱더 응답적이게(responsive) 해준다. 이 강좌에서 비동기 프로그램을 이용하는 컴퍼넌트를 개발하는 완성된 예제를 보여 줄 것이다.

예제에 대해서

  우리는 비동기 프로그래밍에 대한 지원을 하는 컴퍼넌트를 작성하는 방법을 보여주는 예제를 만들 것이다. 또한 여러분은 컴퍼넌트를 동기적으로 호출하는 방법을 일반적으로 사용하고 있다는 것을 명심하고, 우리는 직원의 월급을 계산하도록 해주는 간단한 프로그램을 개발할 것이다. 먼저 동기적으로 작동하는 프로그램을 만들어서 잘 작동되는지 알아보고, 조금씩 비동기 프로그래밍 기능을 하도록 추가할 것이다.

컴퍼넌트 생성하기

  여러분이 만일 VS.NET 을 사용한다면, C#으로 프로젝트의 새로운 컴퍼넌트 라이브러리 타입을 만들면서 시작할 수 있다. VS.NET을 사용하지 않는다면, Text 에디터에서 .cs 파일을 만들고, 라이브러리(DLL)로 컴파일할 수 있다. 다음 코드는 SalaryCalc 컴퍼넌트를 보여준다.

namespace AsyncProgDemo{public class SalaryCalc{	public SalaryCalc()	{	}	public string Calculate()	{	Console.WriteLine("Inside Calculate()...");	Console.WriteLine("Caclulating salaries...");	Console.WriteLine("Done...");	return "ok";	}}}


  여러분이 위에서 보는 소스는 실제 로직이 들어있지 않은 매우 간단한 코드이다. Salarycalc 라는 클래스를 포함하는 AsyncProgDemo라는 네임스페이스를 만든다. 이 클래스는 한 집단의 모든 직원의 월급을 계산하는 Calculate라는 한개의 메서드를 가지고 있다. 다 마쳐지면 메서드는 "OK" 라는 문자열을 리턴한다.

SalaryCalc 컴퍼넌트를 사용하는 클라이언트 프로그램 만들기

  이 컴퍼넌트를 사용하는 콘솔 프로그램을 만들어보자.

using System;namespace AsyncProgDemo{	class Client	{		static void Main(string[] args)		{			SalaryCalc sc=new SalaryCalc();			sc.Calculate();		}	}}


  이 프로그램은 매우 직관적이어서 설명이 필요없을 것이다.

비동기프로그램 컴퍼넌트에 대한 코딩 가이드라인

  실제 코딩에 들어가기 전에, 비동기 컴퍼넌트 설계시 추천할만한 가이드라인이 무엇이 있는지 알아보자.

    ■ 비동기 뿐만 아니라 동기적으로도 메서드를 호출할수 있는 기능 제공

    ■ 필요에 따라 클라이언트(caller 응용프로그램)이 호출되는 메서드의 버전을 결정할수 있도록 하는 기능

    ■ 동기적으로 호출한 메서드를 만들기 위해 클라이언트 응용프로그램을 수정하지 않는다. 클라이언트 는 컴퍼넌트에의해 어떻게 호출되는지 모르도록 진행되어야 한다.

비동기프로그램 메서드에 대한 코딩 가이드라인

  여러분의 비동기 컴퍼넌트는 메서드를 위해서 다음과 같은 가이드라인을 준수해야한다.

    ■ 다음과 같은 시그너쳐를 매칭시키는 컴퍼넌트를 작성한다.

        □ public XXXX()

        □ public IAsyncResult BeginXXXX(AsyncCallback ac, Object state)

        □ public EndXXXX(IAsyncResult result)

  위의 메서드 중에서 XXXX는 메서드 이름을 나타낸다. 예를들어, 앞에서 본 소스의 경우 Calculate, BeginCalculate, EndCalculate 메서드로 쓸 수 있다. EndXXXX 의 리턴 타입은 여러분의 메서드에서 원했던 리턴타입과 같다. (이 경우 string 일것이다)

  BeginXXXX 메서드의 경우 다음과 같은 사항을 기억하자.

    ■ 모든 IN 파라미터를 포함한다.

    ■ 모든 OUT 파라니터를 포함한다.

    ■ 모든 IN/OUT 파라미터를 포함한다.

    ■ 마지막 두개의 파라미터로 AsyncCallback과 object를 받아들인다.

    ■ ISyncResult를 리턴한다.

  EndXXXX 메서드의 경우 다음과 같은 사항을 기억하자.

    ■ 모든 IN/OUT 파라미터를 포함한다.

    ■ 모든 OUT 파라니터를 포함한다.

    ■ IAsyncResult를 마지막 파라미터로 받아들인다.

    ■ 여러분이 원하는 데이터 타입으로 값들을 반환한다.

  우리가 만든 메서드는 다른 파라미터를 포함하지 않았지만 여러분은 다른 메서드들과 마찬가지 방법을 사용할 수 있다.

네임스페이스 포함시키기

  위의 예제가 잘 작동하려면 여러분은 다음과 같은 네임스페이스를 컴퍼넌트에 추가시켜야 한다.

  ■ System

  ■ System.Runtime.Remoting.Messaging

SalaryCalc 변형하기

using System;using System.Runtime.Remoting.Messaging;namespace AsyncProgDemo{public class SalaryCalc{public delegate string CalcDelegate();public SalaryCalc(){}public string Calculate(){	Console.WriteLine("Inside Calculate()...");	Console.WriteLine("Caclulating salaries...");	Console.WriteLine("Done...");	return "ok";}public IAsyncResult BeginCalculate(AsyncCallback ac,Object state){	CalcDelegate cd=	new CalcDelegate(this.Calculate);			IAsyncResult result=	cd.BeginInvoke(ac,state);	return result;}public string EndCalculate(IAsyncResult result){	CalcDelegate cd=(CalcDelegate)	((AsyncResult)result).AsyncDelegate;		object o=cd.EndInvoke(result);	return (string)o;}}}


  여기서, 원래 클래스에서 몇가지 부분을 추가시켰다.

  ■ 위에서 언급한 시그너쳐를 매칭시키는 BeginCalculate 메서드를 추가한다.

  ■ 위에서 언급한 시그너쳐를 매칭시키는 EndCalculate 메서드를 추가한다.

  ■ BeginCalculate 메서드 내부에서 delegate를 끝냈다. 이 메서드는 컴퍼넌트에서부터 callback 을 받은 후에 클라이언트에 의해 호출될 것이다. callback은 Calculate() 메서드가 종료될때 자동으로 호출된다.

클라이언트의 변형된 버전

  이 컴퍼넌트의 비동기적인 특징을 사용하기 위해 우리는 클라이언트를 다음과 같이 바꿀 필요가 있다.

using System;using System.Threading;using System.Runtime.Remoting.Messaging;namespace AsyncProgDemo{class Client{static void Main(string[] args){	SalaryCalc sc=new SalaryCalc();	AsyncCallback ac=new AsyncCallback(MyCallback);	IAsyncResult result=sc.BeginCalculate(ac,sc);	Thread.Sleep(5000);}public static void MyCallback(IAsyncResult result){SalaryCalc sc=(SalaryCalc)result.AsyncState;object o=sc.EndCalculate(result);Console.WriteLine("Inside Callback...");Console.WriteLine("Result of salary Calculation:" + o);}}}


  여기서 Calculate() 메서드를 직접 호출하는 대신에, 우리는 callback 메서드를 호출하는(MyVallback) BeginInvoke 메서드를 호출했고, 결과를 얻었다. 우리는 Calculate 메서드를 직접 호출했을때 같은 결과가 나왔다는 것을 알아두자.

결 론

  .NET은 밑바닥에서부터 비동기 프로그래밍을 지원한다. 여러분은 쉽게 함수를 비동기적으로 기능하게 하는 컴퍼넌트를 개발하게 해준다. 앞에서 우리는 그런 컴퍼넌트를 만드는 방법에 대한 예제를 보았고, 또한 그런 컴퍼넌트 개발을 위한 가이드 라인을 알아보았다.

'programming > c#' 카테고리의 다른 글

.NET Enterprise Services 성능  (0) 2004.12.23
VS .Net에서 Macro를 이용하여 #Region 쉽게 추가하기  (0) 2004.12.14
[펌] COM+ 관련 게시물  (0) 2004.11.12

+ Recent posts