[C#] 인터페이스가 Task를 반환해야하는 경우 작동하지 않는 구현을 수행하는 가장 좋은 방법은 무엇입니까?

아래 코드에서 인터페이스로 인해 클래스 LazyBar는 메서드에서 작업을 반환해야합니다 (인수를 변경할 수 없음). LazyBar신속하고 동 기적으로 실행된다는 점에서 구현이 특이한 경우 -메소드에서 비 작동 태스크를 리턴하는 가장 좋은 방법은 무엇입니까?

Task.Delay(0)아래에 갔지만 함수가 많이 호출되면 성능에 부작용이 있는지 알고 싶습니다 (인수를 위해 초당 수백 번 말하십시오).

  • 이 구문 설탕은 큰 것으로 풀리나요?
  • 내 응용 프로그램의 스레드 풀이 막히기 시작합니까?
  • 컴파일러 식칼은 Delay(0)다르게 처리하기에 충분 합니까?
  • 다를까요 return Task.Run(() => { });?

더 좋은 방법이 있습니까?

using System.Threading.Tasks;

namespace MyAsyncTest
{
    internal interface IFooFace
    {
        Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
    }

    /// <summary>
    /// An implementation, that unlike most cases, will not have a long-running
    /// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
    /// </summary>
    internal class LazyBar : IFooFace
    {
        #region IFooFace Members

        public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
        {
            // First, do something really quick
            var x = 1;

            // Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
            // Is it a real no-op, or if I call this a lot, will it adversely affect the
            // underlying thread-pool? Better way?
            return Task.Delay(0);

            // Any different?
            // return Task.Run(() => { });

            // If my task returned something, I would do:
            // return Task.FromResult<int>(12345);
        }

        #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Test();
        }

        private static async void Test()
        {
            IFooFace foo = FactoryCreate();
            await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
            return;
        }

        private static IFooFace FactoryCreate()
        {
            return new LazyBar();
        }
    }
}



답변

no-op 표현식으로 작성하는 것보다 Task.FromResult(0)또는 사용하면 Task.FromResult<object>(null)오버 헤드가 줄어 듭니다 Task. Task미리 결정된 결과로을 만들 때 예약 오버 헤드가 없습니다.


오늘은 Task.CompletedTask 를 사용 하여이 작업 을 수행하는 것이 좋습니다 .


답변

를 사용하는 것에 대한 Reed Copsey의 답변 에 추가하기 Task.FromResult위해 완료된 작업의 모든 인스턴스가 동일하기 때문에 이미 완료된 작업을 캐시하면 성능을 훨씬 향상시킬 수 있습니다.

public static class TaskExtensions
{
    public static readonly Task CompletedTask = Task.FromResult(false);
}

함께 TaskExtensions.CompletedTask사용하면 전체 응용 프로그램 도메인 전체에 동일한 인스턴스를 사용할 수 있습니다.


닷넷 프레임 워크 (V4.6)의 최신 버전은 추가 단지 그와 Task.CompletedTask정적 속성

Task completedTask = Task.CompletedTask;


답변

Task.Delay(0)허용 된 답변에서와 같이 그것이 완성 된 캐시 된 사본이므로 좋은 접근 방식이었습니다 Task.

4.6 현재 Task.CompletedTask목적에 따라 더 분명한 것이 있지만 Task.Delay(0)여전히 단일 캐시 인스턴스를 반환 할 뿐만 아니라 동일한 단일 캐시 인스턴스를 반환합니다Task.CompletedTask .

의 사용도의 캐시 특성은 일정하게 유지 보장,하지만 구현에 의존 최적화 등이다 구현에 의존 최적화로 (구현은 여전히 유효 뭔가 변경 한 경우 즉, 그들은 여전히 제대로 작동 것) Task.Delay(0)이었다을 허용 된 답변보다 낫습니다.


답변

최근 에이 문제가 발생하여 메소드가 무효라는 경고 / 오류가 계속 발생했습니다.

우리는 컴파일러를 배치하는 사업을하고 있으며 이것을 정리합니다.

    public async Task MyVoidAsyncMethod()
    {
        await Task.CompletedTask;
    }

이것은 지금까지 모든 조언 중 최고의 것을 모은 것입니다. 실제로 메소드에서 무언가를 수행하지 않는 한 return 문은 필요하지 않습니다.


답변

return Task.CompletedTask; // this will make the compiler happy


답변

지정된 유형을 반환해야 할 경우 :

Task.FromResult<MyClass>(null);


답변

Task completedTask = Task.CompletedTask;.Net 4.6 의 솔루션을 선호 하지만 다른 방법은 메소드를 비동기로 표시하고 void를 반환하는 것입니다.

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

경고가 표시되지만 (CS1998-대기 표현식이없는 비동기 함수)이 컨텍스트에서는 무시해도 안전합니다.