4

Implementing an interface that requires a Task return type in synchronous code과 유사하지만 컴파일러 오류를 무시해야하는지 궁금하지만 내 상황이 대신 생성됩니다.작업을 반환하는 인터페이스의 동기 구현

public interface IAmAwesome { 
    Task MakeAwesomeAsync(); 
} 

asyncawait를 사용하여 비동기 적으로 수행되는 멋진 혜택을 일부 구현에서 :

의 나는이 같은 인터페이스를 가지고 있다고 가정 해 봅시다. 이것은 실제로 인터페이스가 허용하려고 시도하는 것입니다.

경우에 따라서는 드문 경우지만 멋진 동기화 방법 만 있으면 멋지게 만들 수 있습니다. 그럼 구현이 같다고 가정하자 :

public class SimplyAwesome : IAmAwesome { 
    public async Task MakeAwesomeAsync() { 
     // Some really awesome stuff here... 
    } 
} 

이 작동하지만, 컴파일러는 경고한다 :

이 방법은 '기다리고'연산자를 부족하고 동 기적으로 실행됩니다. 연산자를 사용하여 비 블로킹 API 호출 인 또는 'await TaskEx.Run (...)'을 기다려 백그라운드 스레드에서 CPU 바운드 작업을 수행하는 것이 좋습니다. 나는이 컴파일러 경고를 무시하도록 선택할 때 무엇을 결정해야한다 -

public class SimplyAwesome : IAmAwesome { 
    public async Task MakeAwesomeAsync() { 
     await Task.Run(() => { 
      // Some really awesome stuff here, but on a BACKGROUND THREAD! WOW! 
     }); 
    } 
} 

내 질문은 :

컴파일러는 실제로이 솔루션을 제안한다? 어떤 경우에는 작업이 너무 간단하여 스레드를 생성하는 것이 명백히 비생산적입니다.

+1

당신이해야할 일은'public interface IAmAwesome { Task MakeAwesomeAsync();입니다. void MakeAwesome(); } '이므로 비동기 및 동기 메서드가 노출됩니다.그러나 현실 세계에서 실용적인 것이 다른 이야기입니다. –

+0

저는 비동기가 아닌 작업을하는 이유가 무엇인지 궁금합니다. 구체적인 유스 케이스를 제공 할 수 있습니까? – JLRishe

+2

@JLRishe 일반적인 경우는 때로는 캐시 될 수있는 일을하는 것입니다. "캐시에서 가져 오기"버전은 동기식 일 수 있으며 캐시 미스 버전은 비동기식입니다. – Servy

답변

10

작업을 동 기적으로 수행하려는 경우 async 메서드가 항상 동 기적으로 실행된다는 것을 알면 상황에 따라 바람직하지만 경고를 무시하십시오. 경고가 무엇을 말하고 있는지 이해하고 설명하는 동작이 정확하다고 생각하면 문제가되지 않습니다. 결국 경고이고 오류가 아닌 이유가 있습니다.

물론 다른 옵션은 메서드 async을 만들지 않고 단지 Task.FromResult을 사용하여 이미 완료된 작업을 반환하는 것입니다. 오류 처리 의미를 변경합니다 (모든 예외를 catch하여 반환하는 태스크로 랩핑하지 않는 한). 적어도 그렇게 염두에 두어야합니다. 결과가 Task 인 경우 예외가 전파되도록하려면 async 메서드를 그대로두고 경고를 표시하지 않는 것이 좋습니다.

+0

경고를 무시하고 클라이언트가 모르는 사이에'await'을 사용하여 메서드를 호출하면 예외가 어떻게됩니까? – Yuck

+0

@Yuck 반환 된 'Task'는'Faulted'이며 예외에 대한 정보를 포함합니다. 그'Task'가 기다릴 때, 그 예외는 다시 던져 질 것입니다. 조작이 실제로 비동기 인 경우와 다를 바는 없습니다. – Servy

6

이 컴파일러 경고를 무시하도록 선택해야하는 경우는 무엇입니까? 어떤 경우에는 작업이 매우 간단하여 스레드를 생성하는 것이 부정 확한 역효과 인 입니다.

컴파일러가 "이 메서드 내부에서 Task.Run 사용"을 나타내지 않습니다.. async 메서드를 준비했으며 메서드 선언에 async 수정자를 추가했지만 실제로 기다리지는 않았다는 것을 알려주는 것입니다.

당신은 세 가지 방법을 취할 수 :

A. 당신은 컴파일러 경고를 무시 수있는 모든 것이 여전히 실행됩니다.상태 머신 생성에는 약간의 오버 헤드가 있지만 메소드 호출은 동 기적으로 실행됩니다. 작업을 수행하는 데 시간이 오래 걸리고 메서드 실행이 차단 호출을 유발할 수있는 경우이 메서드를 사용하는 사용자를 혼동시킬 수 있습니다.

B.는 동기 인터페이스와 비동기 인터페이스에 "최고"의 생성을 분리 : 작업이 너무 많은 시간이 소요되지 않으면

public interface MakeAwesomeAsync 
{ 
    Task MakeAwesomeAsync(); 
} 

public interface MakeAwesome 
{ 
    void MakeAwesome(); 
} 

C., 당신은 단순히 사용 Task에 포장 할 수 있습니다 Task.FromResult. 내가 이것을 선택하기 전에 CPU 바운드 작업을 실행하는 데 걸리는 시간을 정확하게 측정 할 것입니다. 모두가 이미 다른 지적

+0

인터페이스를 분할 할 수없는 경우 Servy의 대답에 동의합니까? – Yuck

+0

작업이 CPU 바운드 작업이 아닌 경우에는 'Task.Result'로 래핑하면됩니다. –

+0

'이것은 코드 소비자를 혼란스럽게 할 것입니다. '이것은 작업이 장기간 실행되는 경우에만 해당됩니다. 작업이 매우 빨리 완료되면 문제가되지 않습니다. 예를 들어 파일 IO에 대한'Stream' 구현은 비동기 적으로 수행하는 번거 로움이 없으므로 시간이 거의 걸리지 않기 때문에 대부분의 "Async"메소드를 동 기적으로 실행하지만 네트워크 IO 구현은 비동기식으로 작업해야하기 때문에 그들은 단지 오래 걸린다. – Servy

4

, 당신은 3 개 가지 옵션이 있습니다, 그래서 의견의 문제 :

  1. async을 제거
  2. 동기화/async 과부하가 경고를 그것을 async를 유지하고 무시 완료된 작업을 반환합니다. 일부 최적화 상태 머신을 생성하고 해제의 약간의 오버 헤드가 async 방법을 만들기

    • : 몇 가지 이유를 들어

      public class SimplyAwesome : IAmAwesome 
      { 
          public Task MakeAwesomeAsync() 
          { 
           // run synchronously 
           return TaskExtensions.CompletedTask; 
          } 
      } 
      

      :

나는 already completed task를 반환 추천 컴파일러가 추가하는 try-catch 블록 때문에 (인라인과 같이).

  • await이 어디인지 궁금한이 코드를 보는 다른 팀 구성원과 경고를 처리해야합니다.
  • 완전 동기화 방법 async을 표시하는 데 다소 불협화음이 있습니다. 그것은 코드에 while(false){}을 추가하는 것과 같지만 동일하게 작동하지만 메서드의 의미를 전달하지는 않습니다.
  • Servy는 작업 반환은 예외 처리의 의미를 변경한다고 지적했습니다. 그것이 사실이지만, 나는 그것이 문제가 아닌 것으로 생각한다. 모든

    첫째, 대부분의 async 코드는 메서드를 호출하고 예외가없이 방법이 async 아닌지 여부를 같은 장소에서 발생하지된다는 의미입니다 같은 장소 (즉 await MakeAwesomeAsync())에서 반환 된 작업을 기다리고 있습니다.

    두 번째로 .Net 프레임 워크의 작업 반환 메서드도 예외를 동 기적으로 발생시킵니다. 예를 Task.Delaythrows an exception directly without storing it in the returned task을 위해 가지고 있으므로 예외를 발생하는 await 작업에 필요가 없습니다 것은 : 닷넷 개발자들이 닷넷에서 동 기적 예외가 발생하는 경우를 제외하고 할 필요가 있기 때문에

    try 
    { 
        Task.Delay(-2); 
    } 
    catch (Exception e) 
    { 
        Console.WriteLine(e); 
    } 
    

    는 합리적인 그들이해야 또한 제외한에서의 당신의 암호.

    +1

    왜이 답변에는 더 많은 upvotes가 없는지 잘 모르겠습니다. IMO, 비동기 적으로 실행되지 않는 메소드에 async 키워드를 사용하지 않는 것이 가장 좋습니다. API에서 반환 유형의 작업은 단순히 메서드 *가 비동기 적으로 실행될 수 있음을 의미합니다. 그것은 보장할만한 것이 아닙니다. 이 메소드의 구현자는 퍼블릭 API에 영향을주지 않으면 서 구현 세부 사항 결정을 내릴 수 있습니다. – jam40jeff

    +1

    또한 .NET 4.6을 두드리면 TaskExtensions.CompletedTask로 펀치를 잡을 수 있습니다. 이는 항상 수행했던 것 (Task.FromResult (0))보다 성능이 좋고 의미가 더 잘 전달됩니다. – jam40jeff

    관련 문제