C# Task-based Asynchronous Pattern - TAP

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

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


http://www.albahari.com/threading/part2.aspx#_Thread_Safety



 Task-based Asynchronous Pattern(이하 TAP)은 .Net framework 4.0에서 나온 개념으로 저 수준의 Thread를 컨트롤하지 않고 고 수준의 Task 레벨에서 비동기를 지원하고 있고 이것을 이용해 비동기 패턴 구현을 권장하고 있다.

 TAP은 단일 메소드를 사용하여 비동기 작업의 시작과 완료를 나타냅니다.이는 APM(Begin, End)과 대조적이다. TAP 메소드는 반환되는 형식에 따라 Task, Task<T>로 반환되고 Task<T>로 반환된 객체는 Result 필드를 통해서 반환된 값을 사용할 수 있다. 우선 간단하게 Task를 이용해서 비 동기 실행 코드를 살펴 보도록 하자. 

/// <summary>
/// TAP 비 동기 수행 테스트
/// </summary>
[TestMethod]
public void TAP_TestMethod_01()
{
    //간단한 비 동기 실행 수행
    Task task = new Task(() => 
    {
        Thread.Sleep(1000);
        Debug.WriteLine("비 동기 실행.");
    });
 
    //타스크를 비동기 실행 시킨다.
    task.Start();
 
    //타스크가 완료가 될 때까지 대기 한다.
    task.Wait();
 
    Debug.WriteLine("비 동기 실행 완료.");
 
    //강제로 성공이라고 표시한다.
    Assert.IsTrue(true);
}

[코드1] Task를 이용해 비 동기 수행 


 "코드1"을 보면 Task를 인스턴스 시키면서 파라메터로 Action을 넘겨준다. 그리고 인스턴스에서 Start()를 호출하여 비 동기로 작업을 수행한다. task.Wait()는 비 동기 작업이 완료되기 전에 메소드를 종료 하는것을 방지 하기 위해 대기하도록 설정하였다. 위와 같은 방법은 이전의 Thread와 별 다를 바 없을 것이다. 그렇다면 다음 코드를 한번 보도록 하자.

/// <summary>
/// Task의 Factory를 통해 TAP 비 동기 수행 테스트
/// </summary>
[TestMethod]
public void TAP_TestMethod_02()
{
    //Task의 Factory를 통해서 타스크를 받아 오는 방법
    var task = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        Debug.WriteLine("비 동기 실행.");
    });
 
    //타스크가 완료가 될 때까지 대기 한다.
    task.Wait();
 
    Debug.WriteLine("비 동기 실행 완료.");
 
    //강제로 성공이라고 표시한다.
    Assert.IsTrue(true);
}

[코드2] Task의 Factory를 통해 Task 생성 후 실행


 "코드2"는 "코드1"과 다른점이 task.Start() 없이 곧바로 수행이 되도록 하고 있다. 그럼 다시 다음 코드를 보고 비교 해  보도록 하자. 

/// <summary>
/// Task<![CDATA[<T>]]>의 Factory를 통해 TAP 비 동기 수행 테스트
/// </summary>
[TestMethod]
public void TAP_TestMethod_03()
{
    var tempValue = 100;
 
    //Task의 Factory를 통해서 타스크를 받아 오는 방법
    var task = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        Debug.WriteLine("비 동기 실행.");
 
        return 100;
    });
 
    //비 동기 실행에서 값이 반활 될때까지 대기하고 
    //반환이 되면 returnValue에 값을 바인딩 한다.
    var returnValue = task.Result;
 
    Debug.WriteLine("비 동기 실행 완료.");
 
    //값이 같으면 성공
    Assert.AreEqual(returnValuetempValue);
}

[코드3] Task<T>형식으로 비 동기 작업 수행 테스트


 "코드3"에서는 지금까지와는 다른 task.Result를 사용하였다. 이 구문은 비 동기로 수행되는 작업이 완료되어 값을 반환 할 때까지 대기하고 값을 할당 해준다. 그런데 왜 비동기를 사용해야 할까? 비 동기를 사용 하면 낮설고, 교착 상태에 빠질 수도 있으며 디버깅 하기도 더 어렵다. 그렇다면 아래 "코드4"를 한번 보길 바란다.

/// <summary>
/// Task<![CDATA[<T>]]>의 Factory를 통해 TAP 비 동기 수행 테스트
/// 여러 타스크를 비 동기로 수행하여 시간 절약을 얻었다.
/// </summary>
[TestMethod]
public void TAP_TestMethod_04()
{
    var tempValue = 450;
 
    Stopwatch sw = new Stopwatch();
    sw.Start();
 
    //Task의 Factory를 통해서 타스크를 받아 오는 방법
    var task1 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(2000);
        Debug.WriteLine("DB1.Server.com에서 DB를 가지고 옴.");
 
        return 50;
    });
 
    //Task의 Factory를 통해서 타스크를 받아 오는 방법
    var task2 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(3500);
        Debug.WriteLine("Socket로 레거시 시스템에서 정보를 가져 옴");
 
        return 150;
    });
 
    //Task의 Factory를 통해서 타스크를 받아 오는 방법
    var task3 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(1500);
        Debug.WriteLine("DB2.Server.com에서 DB를 저장하고 영향 받은 row 갯수를 가져옴.");
 
        return 250;
    });
 
    //비 동기 실행에서 값이 반활 될때까지 대기한다.
    Task.WaitAll(new[] { task1task2task3 });
 
    sw.Stop();
    Debug.WriteLine(sw.ElapsedMilliseconds);  //3504밀리초가 output에 찍혔다.
    Debug.WriteLine("비 동기 실행 완료.");
 
    //returnValue에 비 동기로 수행해 받은 값을 바인딩 한다.
    var returnValue = task1.Result + task2.Result + task3.Result;
 
    //값이 같으면 성공
    Assert.AreEqual(returnValuetempValue);
}

[코드4] 비 동기 수행으로 전체 수행 시간을 빠르게 할 수 있다.


 위 코드를 살펴 보면 외부 시스템(DB, Socket)으로 정보를 가져오고 저장하는 프로세스가 있다. 각 수행 시간이 2000, 3500, 1500 밀리초가 걸린다고 가졍하며 코딩을 하였다. 이 작업을 순차적으로 수행하면 2000 + 3500 + 1500을 모두 합한 7초가 걸린다는 산술적인 계산이 떨어 진다. 그렇지만 위 작업을 비 동기로 수행하면 최대 공약수인 3500밀리초만 걸리다는 것을 알 수 있다. 위 코드에서 sw.ElapsedMilliseconds 코드의 결과값이 3504(컴퓨터 마다 약간의 차이가 발생한다)로 측정이 되었다. 7초와 3.5초라는 단순 비교 만으로도 비 동기 수행을 함으로써 얻을 수 있는 잇점을 장황한 설명을 하지 않아도 알 수 있을 것이다.



Tip!

나중에 ASP.NET MVC에서 IAsyncController을 통해서 비동기 컨트롤을 사용하여 얻을 수 있는 잇점에 대해서도 상세하게 다루도록 하겠다.




 지금까지 TAP를 이용해서 비 동기 작업에 대해서 간단하게 탐색해 보았다. 다음 포스트에서는 지금보다 더 상세하게 알아보는 시간을 가져보도록 하겠다.


------------------------------------------------------------------------------------------


 아래는 MS에서 배포하고 있는 TAP관련 문서이며 번역번도 같이 올려 놓는다. - 번역본은 판교 (이전 가락동)에서 교육을 받을 때 강습생들이 번역한 문서다.


TAP(Task-based Asynchronous Pattern).docx

TAP(Task-based Asynchronous Pattern)(번역본)completed.docx


+ Recent posts