C #에서 Task.FromResult <TResult> 사용은 무엇입니까


189

C # 및 TPL ( Task Parallel Library )에서 Task클래스는 T 유형의 값을 생성하는 진행중인 작업을 나타냅니다.

Task.FromResult 메서드에 무엇이 필요한지 알고 싶습니다 .

즉, 이미 생산 된 가치를 가지고있는 시나리오에서이를 다시 작업으로 랩핑해야합니까?

염두에 두어야 할 것은 Task 인스턴스를 허용하는 다른 메소드의 일부 어댑터로 사용된다는 것입니다.


4
이것이 당신을 도와 줍니까? msdn.microsoft.com/ko-kr/library/hh228607.aspx
Izikon

30
어느 정도까지는 동의하지만, 이와 같이 조밀하고 유용하며 통합 된 토론 중심 페이지를 만드는 것이 큰 이점입니다. 나는 거의 항상 인터넷 검색과 여러 곳에서 연구를 수행하는 것보다 좋고 밀도가 높은 스택 오버 플로우 페이지에서 더 많은 것을 배우 므로이 게시물을 게시하게되어 기쁩니다.
Alex Edelstein

41
Google에서 저를 SO로 데려오고 Google로 가라고 요청합니다. 그것은 순환 참조입니다 :)
gmail 사용자

답변:


258

내가 찾은 두 가지 일반적인 사용 사례가 있습니다.

  1. 비동기 호출자를 허용하는 인터페이스를 구현하지만 구현이 동기식 인 경우
  2. 테스트를 위해 비동기 코드를 스터 빙 / 모의 할 때.

6
# 1의 좋은 사례는 웹 서비스입니다. 리턴되는 동기 서비스 메소드 Task.FromResult와 네트워크 I / O를 위해 비동기 적으로 대기하는 클라이언트가 있을 수 있습니다 . 이 방법으로을 사용하여 클라이언트 / 서버간에 동일한 인터페이스를 공유 할 수 있습니다 ChannelFactory.
Nelson Rothermel

2
예를 들어 ChallengeAsync 메서드입니다. MS의 디자이너들은 WTF를 생각하고 있었습니까? 이 메소드가 태스크를 리턴 할 이유는 없습니다. 그리고 MS의 모든 샘플 코드에는 FromResult (0)가 있습니다. 다행스럽게도 컴파일러는이를 최적화 할만큼 똑똑하고 실제로 새 스레드를 생성하지 않고 즉시 종료하지 않습니다!
John Henckel

14
@JohnHenckel : OWIN은 처음부터 비동기 친화적으로 설계되었습니다. 그냥 있기 때문에 인터페이스와 기본 클래스는 종종 서명 비동기 사용할 수 있습니다 (하지 의 힘 ) 구현은 비동기로. 그것과 비슷 그래서 IEnumerable<T>에서 파생 IDisposable- 그것은 수 있습니다 열거 가능한 일회용 자원하지 않은하는 이에 있습니다. 어느 쪽도 FromResult, async,도 await스레드를 생성하지 않습니다.
Stephen Cleary

4
@StephenCleary hmhm, 설명해 주셔서 감사합니다. 나는 기다림이 스폰 될 것이라고 가정했지만 시도했지만 실패하지 않았습니다. Task.Run 만 수행합니다. 따라서 x = Await Task.FromResult (0); x = 0이라고 말하는 것과 같습니다. 혼란 스럽지만 알아두면 좋습니다!
John Henckel

4
@OlegI : I / O 작업의 경우 가장 좋은 솔루션은 비동기 적으로 구현하는 것이지만 때로는 선택의 여지가없는 경우가 있습니다. 또한, 때때로 당신은 할 수 있습니다 (값이 캐시되지 않은 경우 비동기 구현에 다시 하락, 예를 들어, 캐시 된 결과를) 기적을 구현합니다. 보다 일반적으로,- Task반환 방법은 " 비동기적일 있음"을 의미한다 . 따라서 일부 구현에는 동기식 (예 : NetworkStream비동기식이지만 동기식 이어야 함)을 충분히 알고있는 메소드에 비동기 서명이 제공되는 경우 가 있습니다 MemoryStream.
Stephen Cleary

50

한 가지 예는 캐시를 사용하는 방법입니다. 결과가 이미 계산 된 경우 값을 사용하여 완료된 작업을 반환 할 수 있습니다 (Task.FromResult )을 . 그렇지 않은 경우 계속 진행중인 작업을 나타내는 작업을 반환합니다.

캐시 예 : 미리 계산 된 값에 Task.FromResult를 사용하는 캐시 예


에서 반환 된 작업과 같은 완료된 작업을 Task.FromResult캐시 할 수 있습니다.
Paulo Morgado

1
@Paulo : 전체 Task 객체를 메모리에 유지하는 것은 결과를 캐싱하는 것보다 훨씬 낭비 적입니다.
Ben Voigt

2
"가치 작업"이 이미 캐시되어 있어야합니다. 정확히 어떤 것을 기억하지는 않지만 생각합니다 Task.FromResult(0).Task.FromResult(1) , Task.FromResult(false)Task.FromResult(true)캐시됩니다. 네트워크 액세스를 위해 작업을 캐시하지 않아도되지만 결과적으로 완벽하게 처리됩니다. 값을 반환해야 할 때마다 하나씩 생성 하시겠습니까?
Paulo Morgado

4
... 내 자신의 질문에 대답하기 위해, 작업 캐시의 이점은 일부는 완료된 작업이고 나머지는 아직 완료되지 않은 것일 수 있다는 것입니다. 발신자는 신경 쓸 필요가 없습니다. 그들은 비동기식 호출을하고, 이미 완료된 경우, 기다리면 즉시 응답을 받고, 그렇지 않은 경우 나중에받습니다. 이러한 캐시 된 작업이 없으면 (a) 발신자와 발신자가 번거로운 두 가지 메커니즘, (b) 발신자가 이미 사용 가능한 응답을 요청할 때마다 동적으로 작업을 생성해야합니다 ( 우리는 TResult 만 캐시했습니다.)
ToolmakerSteve

1
이제 이해가된다. 답의 문구는 약간 혼란 스러웠다. 작업 자체에는 내장 된 "캐싱"메커니즘이 없습니다. 그러나 .... .... 파일 다운로드, Task <File> GetFileAync ()에 대한 캐싱 메커니즘을 작성한 경우 Task.FromResult (cachedFile)을 사용하여 이미 캐시에있는 파일을 즉시 반환 할 수 있습니다. 스레드 스위치가 없어 시간을 절약하면서 동기식으로 실행됩니다.
Brain2000

31

async 키워드를 사용하지 않고 대기 가능한 메소드를 작성하려는 경우 사용하십시오. 이 예제를 찾았습니다.

public class TextResult : IHttpActionResult
{
    string _value;
    HttpRequestMessage _request;

    public TextResult(string value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage()
        {
            Content = new StringContent(_value),
            RequestMessage = _request
        };
        return Task.FromResult(response);
    }
}

여기에서는 웹 API 작업에 사용되는 IHttpActionResult 인터페이스의 자체 구현을 만듭니다. ExecuteAsync 메서드는 비동기식이어야하지만 비동기 키워드를 사용하여 비동기식 및 대기 가능하게 만들 필요는 없습니다. 이미 결과가 있고 기다릴 필요가 없으므로 Task.FromResult를 사용하는 것이 좋습니다.




1

코드에서 다른 독립적 인 작업을 수행하는 동안 완료하는 데 시간이 오래 걸리는 동기식 메서드에 Task.FromResult를 사용할 수 있다고 주장합니다. 오히려 오히려 메서드를 비동기 호출하도록하십시오. 그러나 호출 된 코드를 제어 할 수없고 암시적인 병렬 처리를 원하는 상황을 상상해보십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.