[C#] Async,Await의 내부

C# 2016.08.29 15:32

원본 https://github.com/pjc0247/behind_async_await


behind_async_await

C#은 stackless한 코루틴을 지원합니다. 어케 가능한지 아라보자

static async void Foo()
{
    Console.WriteLine("A");

    await Task.Delay(1000);

    Console.WriteLine("B");

    await Task.Delay(1000);

    Console.WriteLine("C");
}

아래의 코드는 Foo 함수를 디컴파일 한 결과물을 기반으로 다시 작성되었습니다. 대충 필요한것만 남기고 생략함

class MyAsync : System.Runtime.CompilerServices.IAsyncStateMachine
{
    internal AsyncVoidMethodBuilder builder { get; set; }
    internal int ptr { get; set; }

    public void MoveNext()
    {
        var _this = this;

        switch(ptr)
        {
            case 0:
                {
                    Console.WriteLine("A : " + ptr.ToString());
                    var task = Task.Delay(1000).GetAwaiter();
                    builder.AwaitUnsafeOnCompleted(ref task, ref _this);

                    ptr++;
                    break;
                }

            case 1:
                {
                    Console.WriteLine("B : " + ptr.ToString());
                    var task = Task.Delay(1000).GetAwaiter();
                    builder.AwaitUnsafeOnCompleted(ref task, ref _this);

                    ptr++;
                    break;
                }

            case 2:
                {
                    Console.WriteLine("C : " + ptr.ToString());
                    break;
                }
        }
    }

    public void SetStateMachine(IAsyncStateMachine stateMachine)
    {
    }
}

var async = new MyAsync();
var builder = AsyncVoidMethodBuilder.Create();
async.ptr = 0;
async.builder = builder;
builder.Start(ref async);
  • async가 붙은 메소드는 IAsyncStateMachine를 구현하는 클래스로 변환됩니다.
  • IAsyncStateMachine는 MoveNext 메소드를 정의합니다.
  • MoveNext는 계속 실행됩니다. MoveNext 내부의 상태(실행 포인터) 관리는 클래스 내부의 구현체에서 직접 해야합니다.
  • AwaitUnsafeOnCompleted는 어떠한 Task가 완료되면 다시 MoveNext를 호출하도록 예약하는 역할을 합니다.
  • 이 작업이 반복되면서 await/async가 동작하게 됩니다.

결론

  • stackless 코루틴은 stackful 코루틴처럼 사기군같은 컨텍스트 스위칭 없이 자체 상태머신을 이용한 멀쩡해보이는 방법으로 구현한다.
  • 컴파일러가 자동으로 코드를 길게 풀어준다.
  • 사기군같은 stackful 코루틴은 https://github.com/pjc0247/jwgtrich


'C#' 카테고리의 다른 글

[C#] Linq.Expression Snippets  (0) 2016.09.22
[C#] Async,Await의 내부  (0) 2016.08.29
[C#] async void / Task  (0) 2016.07.18
[HTTP] 웹소켓 핸드쉐이킹  (2) 2016.06.28
[C#] Mono 환경인지 구분하기  (0) 2016.06.21
[NUnit] Callback 방식의 API 테스트하기  (1) 2016.06.16
Posted by pjc0247
TAG AsyncAwait, C#

C++에는 없지만 다른 언어에는 존재하는 ToString 기능이 부러워서 만들어 보았습니다.


소스 코드와 사용법 : https://github.com/pjc0247/to.cpp



대략적인 사용법은 아래와 같습니다.



* 다른 곳에서 std::to_string과 뭐가 다르냐는 소리를 하도 들어서 추가로 적는 부분


std::to_string은 C++의 기본타입들에대해서만 문자열 변환 기능을 제공합니다. 심지어 STL 컨테이너조차도 문자열화가 불가능합니다.


to.cpp는 STL 컨테이너 뿐만 아니라 유저 클래스에 대해서도 문자열화가 가능합니다. 유저 클래스는 사용자가 to_string 메소드를 생성하여 이 클래스가 어떻게 문자열화되어야하는지 구성할 수 있습니다. (다른 언어와 동일)

to_string 메소드를 구현하지 않은 경우에도, 최소한 클래스 이름과 메모리 주소값은 찍어주기 때문에 두개의 오브젝트가 같은지 다른 인스턴스인지는 구분할 수 있습니다.


또한 유틸리티 기능인 CREATE_TO_STRING 매크로를 제공합니다. 이는 자동으로 클래스에 대해서 to_string 메소드를 만들어줍니다. 자세한 사항은 github 를 참조하세요.

Posted by pjc0247

[C#] async void / Task

C# 2016.07.18 14:50

공통점
* 둘다 메소드 본문이 다 실행되기도 전에 리턴한다. 정확히는 첫번째 await 를 만나기 전까지는 계속 실행되고, 첫번째 await를 만나면 리턴한다.

void 의 경우
* 익셉션이 발생하면 UnhandledException으로 간주되고 프로그램이 종료된다. (.NET 런타임이 이 메소드가 익셉션을 내는지 안내는지를 감시한다)

Task 의 경우
* .NET 런타임이 감시하지 않는다. 유저가 예외처리를 해야 함

* 발생한 익셉션은 리턴값 TaskException에 채워진다 

* 또는 await 사용시, 해당 시점에서 익셉션이 발생한다.

* (유저가 예외처리를 해야하지만 암것도 안했을 경우) 익셉션이 발생해도 아무일도 없는 것 처럼 보인다. 

* 암것도 안했을 경우 TaskScheduler.UnobservedTaskException 콜백이 실행된다. (익셉션 발생 즉시 실행되지 않고 GC가 Task를 정리하려고 했는데, 유저가 익셉션 처리를 안한 경우에 트리거된다.)




언제 써야 할까

void : 최상위 작업인 경우, 이 메소드는 대기될 필요도 없어야 하고, 실제로 async void는 대기시킬 방법도 없다. async void는 단순히 그냥 함수인데 await 키워드를 쓰고싶은 함수라고 간주하면 된다. 주로 이벤트 핸들러에 사용된다.

Task : 이 메소드는 대기될 수 있다. 이 메소드 호출자가 이 메소드 실행을 기다려야(await) 할 필요가 있는 경우, 메소드 이후에 연속된 작업(ContinueWith)이 있어야 하는 경우. Task는 단순히 Task<Void> 라고 생각하면 된다.


'C#' 카테고리의 다른 글

[C#] Linq.Expression Snippets  (0) 2016.09.22
[C#] Async,Await의 내부  (0) 2016.08.29
[C#] async void / Task  (0) 2016.07.18
[HTTP] 웹소켓 핸드쉐이킹  (2) 2016.06.28
[C#] Mono 환경인지 구분하기  (0) 2016.06.21
[NUnit] Callback 방식의 API 테스트하기  (1) 2016.06.16
Posted by pjc0247
TAG async, C#