완료된 작업 만들기


197

완성 된 Task(아닌 Task<T>) 을 만들고 싶습니다 . 이를 위해 .NET에 내장 된 것이 있습니까?

관련 질문 : 완료된 작업 생성 <T>


2
It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well.이것이 어떤 문제라고 생각하십니까? 단일 Task을 캐시하면 전체 프로그램이 1 비트의 추가 메모리를 차지합니다. 즉 없습니다 아무것도 . 또한 그렇게하지 않고 완성 된 작업을 만들 수 있습니다.
Servy

10
오, 실망은 여분의 메모리를 사용해야하는 것과 관련이 없습니다. 코드의 어느 곳에서나 가비지 값이 우아하지 않다는 것입니다.
Timothy Shields

1
오늘 ValueTask완료된 작업 (예 : 코드가 본질적으로 동기가되도록 이미 보유한 값)이 있으므로 할당이 절약됩니다.
nawfal

답변:


246

닷넷 (V4.6)의 최신 버전 단지를 추가, 내장 Task.CompletedTask :

Task completedTask = Task.CompletedTask;

이 속성은 잠금이없는 싱글 톤으로 구현되므로 거의 항상 동일한 완성 된 작업을 사용하게됩니다.


1
방금 최신 VS 14 CTP를 확인하고 4.5.3 프로젝트를 만들었지 Task.CompletedTask만 여전히 내부에 있습니다.
피터 리치

1
2. 최신 CTP (4이며 해당 사이트에서 링크 됨)를 다운로드하지 않았거나 버전 4.5.3을 지정하지 않았습니다. 내 컴퓨터에있는 내용은 다음과 같습니다 . @PeterRitchie
i3arnon

Azure의 Visual Studio 14 이미지에서 VM을 만들었습니다.
피터 리치


모노 5.4.1.7을 사용하는 Mac OS X에서 작업 중이며 동일한 오류가 발생합니다. 이 문제를 어떻게 해결할 수 있습니까?
Khaled Annajar

152

Task<T>암시 적으로 Task로 변환 가능하므로 Task<T>( T임의의 값으로) 완성 된 것을 사용하십시오. 이와 같은 것을 사용하여 실제 결과가 어딘가에 있다는 사실을 숨길 수 있습니다.

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

결과를 공개하지 않고 작업이 항상 완료되었으므로 단일 작업을 캐시하고 재사용 할 수 있습니다.

.NET 4.0을 사용 중이고없는 경우 FromResult다음을 사용하여 직접 만들 수 있습니다 TaskCompletionSource.

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

8
4.0을 사용하는 경우 Microsoft.Bcl.Async 라이브러리를 추가하여 TaskEx.FromResult를 얻을 수있을뿐만 아니라 WhenAll
Carl

@Servy FromResult (false)와 FromResult (true)에서 무엇을 변경합니까?
프란체스코 보니 치

3
@FrancescoB. 결과를보고 있으면 결과의 부울 값이 변경됩니다. 결과를 무시하고 있다면 결과가 중요하지 않습니다.
Servy

66

이를 위해 내가 선호하는 방법은 Task.WhenAll()인수없이 호출 하는 것입니다. MSDN 문서 상태는 "제공된 배열 / 열거 더 작업을 포함하지 않는 경우, 반환 작업은 RanToCompletion 상태로 즉시 전환이 호출자에게 반환의 뜻 전에.". 그것은 당신이 원하는 것 같습니다.

업데이트 : Microsoft의 Reference Source 에서 소스를 찾았습니다 . Task.WhenAll에 다음이 포함되어 있습니다.

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

따라서 Task.CompletedTask는 실제로 내부이지만 인수없이 WhenAll ()을 호출하면 노출됩니다.


9
그것은 해키처럼 느껴지지만 문서의 지원을받습니다. 그래서 나는 몰라요.
sara

2
나와 내 .NET 4.5.2 제한 코드는 충분히 우아합니다. 감사!
Stas Ivanov

36

사용 Task.Delay(0)합니다. 내부적으로 complete의 캐시 된 인스턴스를 반환합니다 Task<T>. 이것은 현재 답변이 어쨌든 제안하는 것입니다. 지금은 인스턴스를 직접 캐시 할 필요가 없으며 코드에 불필요한 가비지 값이 없습니다.

Task.Yield()대신 사용할 수 있다고 생각할 수도 있지만의 결과 Task.Yield()는 의 하위 유형 이 아니며Task 결과는 Task.Delay(0)입니다. 그것은 둘 사이의 미묘한 차이점 중 하나입니다.


30

Task.FromResult (.NET 4.5)를 사용하여 완료된을 반환 할 수 있습니다 Task<T>.

제네릭이 아닌을 필요로하는 경우 의 하위 클래스 이므로 Task항상 사용 Task.FromResult(0)하거나 유사 할 수 있습니다 .Task<T>Task


11

.Net 4.6 이상의 경우

return Task.CompletedTask;

낮은 버전의 경우 사용할 수 있습니다

return new Task(() => { });

3
4.6 이전의 접근 방식에는 조심하십시오! 작업을 시작해야합니다. 그렇지 않으면 완료되지 않습니다! return Task.Delay(0);대신 에 사용 하는 것은 어떻습니까?
Miquel


0

어때요?

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

마음에 들지 않으면 경고 억제를 생략 할 수 있습니다.


방법을 표시해 async도 사용하지 않더라도 전체 상태 머신 장치가 여전히 생성되므로 빈 작업을 반환하는 것이 리소스 부족 시나리오에 더 효과적입니다.
Calvin Fisher
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.