2014-11-12 2 views
14

나는기다리고 있습니다 또는 Task.FromResult

public interface ISomeService 
{ 
    Task<bool> DoSomeExpensiveCheckAsync(string parameter); 
} 

, 하나 개의 서비스가 말할 수있는 그리고 서비스를 소비하는이 클래스를 가지고있다. 몇 가지 간단한 null 검사를 수행 한 다음 서비스 응답을 다시 반환하면됩니다.

public class SomeServiceConsumer 
{ 
    private readonly ISomeService _serviceClient; 

    public SomeServiceConsumer(ISomeService serviceClient) 
    { 
     _serviceClient = serviceClient; 
    } 

    public async Task<bool> DoSomething1Async(string someParameter) 
    { 
     if (string.IsNullOrWhiteSpace(someParameter)) 
     { 
      return false; 
     } 
     return await _serviceClient.DoSomeExpensiveCheckAsync(someParameter); 
    } 

    //No async or await keywords 
    public Task<bool> DoSomething2Async(string someParameter) 
    { 
     if (string.IsNullOrWhiteSpace(someParameter)) 
     { 
      return Task.FromResult(false); 
     } 
     return _serviceClient.DoSomeExpensiveCheckAsync(someParameter); 
    } 
} 

나는 DoSomething1Async 또는 DoSomething2Async해야합니까? this answer에 따르면,

나는 불필요한 await으로 포장하지 말아야하지만 나는 DoSomething2Async

같이 shortcircuiting 그러나 try/catchusing 계산서를 가진 경우가 this answer에 따라 대한 Task.FromResult(false)를 사용할 필요가 어디 전엔 await을해야 돌아 오는 중. 당신은 반환하려는 경우 try/catch 또는 using 그때 내가 await

  • 그렇지 않으면하지 await해야 사용해야하는 경우

    1. , 내가 다음 말에 수정하고있다. 그리고 단락

    에 대한 Task.FromResult을 사용 나는 DoSomething1Async 더 좋아 누군가가 말한다 사방 경우가 : 문제가 나던 것을하고 싶어.

  • 답변

    13

    당신이 그것에 대해 걱정하는 경우, 캐시 Task 다음 async 키워드는 적절한 스택 추적과 함께 Task 반환의 예외를 래핑

    static readonly Task<bool> falseTask = Task.FromResult(false); 
    

    . 그것은 상충 관계이며 perf의 행동 안전입니다.

    각각 다른 것의 차이 시나리오 볼 수 있습니다 :

    async Task UseSomething1Async(string someParameter) 
    { 
        // if IsNullOrWhiteSpace throws an exception, it will be wrapped in 
        // the task and not thrown here. 
        Task t1 = DoSomething1Async(someParameter); 
    
        // rather, it'll get thrown here. this is best practice, 
        // it's what users of Task-returning methods expect. 
        await t1; 
    
        // if IsNullOrWhiteSpace throws an exception, it will 
        // be thrown here. users will not expect this. 
        Task t2 = DoSomething2Async(someParameter); 
    
        // this would never have been reached. 
        await t2; 
    } 
    

    그냥 여기에 요점을 설명 - IsNullOrWhiteSpace 실제로 어떤 이유로 예외를 throw하지 않습니다.

    스택 추적이 수행되는 한 비동기 스택 추적은 await에 의해 결정됩니다. No await은 스택 추적에서 메소드가 사라짐을 의미합니다.

    라고 말하면 DoSomeExpensiveCheckAsync은 예외를 throw합니다. DoSomething1Async의 경우 스택 추적은 caller -> DoSomething1Async -> DoSomeExpensiveCheckAsync처럼 보입니다.

    DoSomething2Async의 경우 스택 추적은 caller -> DoSomeExpensiveCheckAsync입니다. 코드의 복잡성에 따라 디버그하기가 어려울 수 있습니다.

    실제적으로 예외가 던져 지거나 메서드 이름이 단순히 다른 오버로드로 전달되는 단순한 것이라는 것을 알았다면 실제로는 일반적으로 Task을 반환합니다.이 규칙에는 항상 예외가 있습니다. 성능을 최대화하려는 장소가 있어야합니다. 선택하고 신중하게 선택하면, 당신과 당신의 삶을 더 힘들게 만들 수 있다는 것을 깨달으십시오.

    +0

    감사합니다. 나는 그것이 행동의 안전에 어떻게 영향을 미치는지 이해하지 못한다. @ I3arnon의 답변에 대한 내 의견을 참조하십시오. – labroo

    +0

    설명을 편집했습니다. –

    4

    은 실제로 중요하지 않습니다. 항상 Task - async 키워드를 사용하여 다시 표시하는 것이 편한 경우 DoSomething1을 사용하십시오. 당신이 말했듯이

    , 그것은 트레이드 오프입니다 :

    • DoSomething2

      async 방법에 필요한 상태 머신을 생성하지 않으며 그래서 약간 더 빨리이다 (하지만 그 차이가 거의 무시할 수있다).
    • 은 다른 한편으로 그것은 async 방법에 예외가 반환 된 Task에 저장됩니다 다른에 정기적으로 던져 질 것이기 때문에 예외 처리에 관한 몇 가지 예상치 못한 부작용이있을 수 있습니다.

    +0

    예외 차이점을 이해하지 못합니다 @ I3arnon. 서비스에서 DoSomeExpensiveCheckAsync를 명시 적 예외가 발생하면 "var from1 = someServiceCustomer.DoSomething1Async ("Hello ");를 기다립니다." 및 " var from2 = someServiceCustomer.DoSomething2Async ("Hello ");를 기다립니다." 똑같은 예외를 던집니다. DoSomething1Async에는 stacktrace에 여분의 TaskAwaiter.ThrowForNonSuccess가 있습니다. 그것은 DoSomething1Async가 뭔가를하고 있다는 것을 보여 주지만, 나는 부당한 부작용을 얻지 못합니다. – labroo

    +0

    @labroo 차이점을 이해하려면'await'없이 무엇이 일어날 지 생각해보아야한다 :'var task = DoSomethingAsync ("Hello")'. 예외가 있고 메서드가 async이면 예외를 throw하지 않습니다. 예외는 태스크에 저장되고'await'에서 재실행됩니다. 메서드가 비동기가 아닌 경우 다른 메서드와 마찬가지로 예외가 throw됩니다. – i3arnon

    +0

    @labroo 다음은 추가 정보입니다. http://stackoverflow.com/a/24441859/885318 – i3arnon

    관련 문제