Task-based Asynchronous Pattern Task.Yield()

http://blog.stephencleary.com/2012/08/async-coroutines.html

http://msdn.microsoft.com/ko-kr/library/system.threading.tasks.concurrentexclusiveschedulerpair.aspx

http://blog.stephencleary.com/2012/08/async-and-scheduled-concurrency.html

http://msmvps.com/blogs/jon_skeet/archive/tags/Eduasync/default.aspx



 이번 포스트에서는 Task에서 실행되는 주기를 컨트롤 할 수 있는 객체 중에 기본 TaskFactory대신 배타적인 실행 주기로 수행하는 ConcurrentExclusiveSchedulePair 클래스를 사용하여 스케줄링 하는 방법을 알아 보자. 이 코드는 Consone 프로젝트에서 테스트를 진행 하였다.

static void Main(string[] args)
{
    Program p = new Program();
    p.TAP_Yield_TestMethod();
 
    Console.ReadKey();
}
 
#region Task test the Yield method
//배타 스케줄에서 Task 스케줄 확인
public async void TAP_Yield_TestMethod()
{
    var task = MainAsync();
    task.Wait();
}
 
/// <summary>
/// 배타적으로 Task가 실행되는 scheduler.
/// </summary>
private static TaskFactory coroutineFactory = new TaskFactory(new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler);
 
//기본 TaskFactory 선언 방법
//private static TaskFactory coroutineFactory = new TaskFactory();
 
/// <summary>
/// 기본 TaskFactory 대신 재 정의 한 TaskFactory를 통해 Task 생성하여 실행
/// </summary>
private static async Task RunCoroutineAsync(Func<Task> coroutine)
{
    //배타 실행 스케줄로 세팅된 TaskFactory
    //StartNew로 만들어진 Task를 배타 실행되는 스케줄로 관리가 되도록 컨트롤 한다.
    await await coroutineFactory.StartNew(coroutine);
}
 
/// <summary>
/// 여러 루틴을 한번에 실행 하도록 함
/// </summary>
/// <returns></returns>
static async Task MainAsync()
{
    var coroutines = new[]
{
    RunCoroutineAsync(FirstCoroutine),
    RunCoroutineAsync(SecondCoroutine),
    RunCoroutineAsync(ThirdCoroutine),
};
 
    //모두 완료가 될 때가지 대기 한다.
    await Task.WhenAll(coroutines);
}
 
//첫번째 실행
private static async Task FirstCoroutine()
{
    Console.WriteLine("Starting - Zone #1");
    Console.WriteLine("Yielding - Zone #1");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("Returned - Zone #1");
    Console.WriteLine("Yielding again - Zone #1");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("Returned - Zone #1");
    Console.WriteLine("Finished - Zone #1");
}
 
//두번째 실행
private static async Task SecondCoroutine()
{
    Console.WriteLine("  Starting - Zone #2");
    Console.WriteLine("  Yielding - Zone #2");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("  Returned - Zone #2");
    Console.WriteLine("  Yielding again - Zone #2");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("  Returned - Zone #2");
    Console.WriteLine("  Yielding again - Zone #2");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("  Returned again - Zone #2");
    Console.WriteLine("  Finished - Zone #2");
}
 
//세번째 실행
private static async Task ThirdCoroutine()
{
    Console.WriteLine("    Starting - Zone #3");
    Console.WriteLine("    Yielding - Zone #3");
 
    //배타 실행 스케줄에서 Task가 실행 됨으로 다음 Task에 실행 수행을 넘긴다.
    await Task.Yield();
 
    Console.WriteLine("    Returned - Zone #3");
    Console.WriteLine("    Finished - Zone #3");
}
#endregion

[코드1] Exclusive TaskFactory


 위 코드를 Console를 통해 확인해 보자. 확인 된 결과는 "그림1"을 통해 확인할 수 있다.


[그림1] Exclusive TaskFactory 실행 화면


 실행이 Task.Yield()를 만났을 때마다 다음 Task가 실행되는 것을 확인 할 수 있다. 그러다면 아래와 같이 Default TaskFactory를 통해 배타수행과 비교를 해 보도록 하자. 아래 "코드2" 처럼 수정해 보도록 하자.


private static TaskFactory coroutineFactory = new TaskFactory();

[코드2] Default TaskFactory를 활성화 하는 코드



 "코드1"에서 "코드2" 부분을 주석 해제 하여 활성화 하여 테스트를 해 보았다. "그림2"를 통해 확인할 수 있다. 


[그림2] Default TaskFactory를 통해 실행된 화면



 위 소스를 보고 직접 실행 스케줄에 대해서 테스트를 해 보면서 수행 순서에 대해서 이해를 해 보도록 하자. 이와 같이 별도의 스케줄러를 생성하여 원하는 대로 Task를 수행할 수 있도록 커스터마이징도 할 수 있다.


 이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다.

ing™       


+ Recent posts