2012-12-11 2 views
3

내 자신의 비동기 메서드를 구현하는 가장 좋은 방법은 알고 싶습니다. 나는 this article을 읽었으며 sync 메소드를 태스크에 래퍼하여 비동기 메소드로 사용하는 것은 좋지 않다고 말한다. 왜냐하면이 방법은 다른 스레드를 사용하고 더 많은 리소스를 사용하기 때문에 비동기 사용으로 피하기를 원하기 때문이다.올바른 방법으로 내 비동기 메소드를 구현하는 방법은 무엇입니까?

기사에서 TaskCompletionSource를 사용합니다. 그러나 정확히 어떻게 사용하는지 모르겠습니다. TaskCompletionSource의 목적은 무엇입니까?

답변

4

async 메서드를 작성하는 가장 좋은 리소스는 Task-based Asynchronous Pattern (TAP) document by Stephen Toub입니다. 이 문서의 정보 대부분은 part of the official MSDN documentation입니다.

튜토리얼을 더 짧게하려면 (자습서) async/await intro blog post을 권하고 거기에 몇 가지 다른 자습서가 있습니다. async에 대해 조금 배웠 으면 다음 좋은 리소스는 official async/await FAQ입니다.

채널 9에는 수많은 async 개의 동영상이 있습니다. 많은 사람들 (대부분?)은 여전히 ​​CTP 였을 때 async을 논의하지만 제작에 들어갔을 때 디자인 변경이 거의 이루어지지 않았습니다.

특정 질문에 대답하려면 기존 비동기 작업 (예 : I/O 작업, 타이머 또는 이벤트)을 중심으로 Task 래퍼를 만드는 데 TaskCompletionSource이 사용됩니다. 코드 TaskTaskCompletionSource으로 생성 할 수 없습니다. Task에 코드를 실행하려면 Task.Run을 사용해야합니다.

+0

하지만 task.Run을 사용하면 새 스레드가 생깁니다. 잘못이 아니라면 새 스레드가 생기고 더 많은 자원을 사용하고 확장 성이 떨어지기를 피하려고합니다. 새 스레드를 만들지 않고 작업에서 코드를 실행할 수 있습니까? –

+0

어디에서 코드를 실행할 것입니까? –

+0

참. 그런 다음 killercam과 같은 코드를 사용하면 doinf이고 비동기 메서드를 만드는 작업에서 sync 메서드를 래핑하는 것과 같습니다. 이것이 사실이라면 내 게시물의 기사에서 autor는 이것이 좋은 습관이 아니라고 말합니다. –

2

다른 async 메서드 (.NET 5.0 async 키워드 사용) 내에서 메서드를 호출하는 것이 좋습니다. 나는 당신의 질문을 완전히 이해하고 있는지 확신 할 수 없지만, 다음의 간단한 예를 들어보십시오. 해야 모호한 우리가 async 수정을 치료하는 컴파일러를 알려줍니다

Task<int> GetPrimesCountAsync(int start, int count) 
{ 
    return Task.Run(() => 
     ParrallelEnumerable.Range(start, count).COunt(n => 
      Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0))); 
} 

여기

async void DisplayPrimes() 
{ 
    int result = await GetPrimesCountAsync(2, 10000); 
    Console.WriteLine(result); 
} 

오히려 식별자보다 키워드로 기다리고 쓸 수 시작 int와 카운트 사이의 소수를 표시하려면 그 방법 안에서 발생한다. 이렇게하면 C# 5.0 이전에 작성된 코드가 식별자로 기다릴 수 있으므로 오류없이 컴파일됩니다. 비동기 한정자는 void 또는 Task/Task<TResult>을 반환하는 메서드 및 람다 식에만 적용 할 수 있습니다.

await 표현식이 발생하면 실행자는 반복자에서 yeild return과 같이 호출자에게 반환됩니다. 하지만 돌아 오기 전에 런타임은 기다린 작업에 계속 작업을 연결하여 작업이 완료되면 실행이 다시 중단 된 지점에서 계속 실행되도록합니다. 위의 방법으로 컴파일러에서 변환 한 내용을 표시 할 수 있다고 가정합니다.

void DisplayPrimesCount() 
{ 
    var awaiter = GetPrimesCountAsync(2, 100000).GetAwaiter(); 
    awaiter.OnCompleted(() => 
    { 
     int result = awaiter.GetResult(); 
     Console.WriteLine(result); 
    }); 
} 

이 정보가 도움이되기를 바랍니다.


편집. 그래서 작업 차단을 방지하기 위해, 당신은 당신이

private async Task<bool> TestAsync() 
{ 
    return await Task.Run(() => 
    { 
     // Do stuff non-blocking.    
     return true; 
    }).ConfigureAwait(continueOnCapturedContext:false); 
} 

여기 TestAsync 것이다 '수준까지'만들려는 async 과정을 가지고해야합니다 (당신이 어떤 코드를 게시하지대로 사건이 무엇인지 이야기하기 어렵다) UI 컨텍스트 대신 스레드 풀 스레드에서 "return"문을 실행하여 완료 할 수 있어야합니다. 그러면 발신자에게 즉시 반환되지만, 계속 Task.Result을 사용하면 어떤 예외도 AggregateException에 싸여 져서 처리해야합니다.

좋은 설명은 on MSDN here입니다. async/await에 들어가기 전에 C# 4.0 Tasks에 대해 배우기를 권합니다. 동시성을 더 잘 이해할 수 있습니다.

+1

나는 올바르게 기사를 이해하고 있는데, 문제는 Tas.Run을 사용하면 새로운 스레드를 생성하고 더 많은 리소스를 사용하므로 objiveive가 비동기 메소드에 대한 새 스레드를 사용하지 않는다는 것입니다. 문제는 순간적으로, 태스크없이 비동기 메소드를 구현하는 방법을 알지 못한다는 것입니다. 실행을 차단하고 UI를 차단하지 마십시오. 이 기사에서는 TaskCompletionSource를 사용하여 새로운 스레드를 생성하지는 않지만 올바른 방법으로 사용하는 방법을 알지 못합니다. –

+0

좀 더 명확히하기 위해 편집을 참조하십시오. – MoonKnight

+1

본질적으로 항상 두 번째 스레드가 포함되어 있기 때문에 "비동기"를 실행하는 개념을 오해하고있는 것처럼 들립니다. 추가 스레드를 작성/삭제하는 데 익숙하지 않은 경우, 사안이 처리 될 때까지 대기하는 추가 스레드를 하나 만들 수 있습니다 (Busy Loop 없음). 기본적으로 자원을 재사용합니다. 단점은 실행 당 하나의 비동기 요청 만 처리 할 수 ​​있지만 작동합니다. – Mario

관련 문제