170

async / await를 사용하고 있습니다.Task제비 뽑기 그러나 결코 사용하지 않고 있었던Task.Yield()모든 설명이 있더라도 솔직히 말해서 나는 왜 내가이 방법을 필요로하는지 이해하지 못한다.

누군가 좋은 예를들 수 있습니까?Yield()필요한가요?

3 답변


173

사용하면async/await, 당신이 할 때 당신이 전화하는 방법에 대한 보장은 없습니다await FooAsync()실제로 비동기 적으로 실행됩니다. 내부 구현은 완전히 동기식 경로를 사용하여 자유롭게 반환 할 수 있습니다.

차단하지 않고 비동기 적으로 일부 코드를 실행하는 API를 만드는 경우 호출 된 메소드가 동기식 (효과적으로 블로킹)으로 실행될 가능성이 있습니다.await Task.Yield()메소드가 비동기로 강제 실행되고 그 시점에서 제어가 리턴됩니다. 나머지 코드는 현재 상황에서 나중에 실행될 것입니다 (이 시점에서 여전히 동기식으로 실행될 수 있습니다).

이는 "장기 실행"초기화가 필요한 비동기 메서드를 만드는 경우에도 유용합니다 (예 :

 private async void button_Click(object sender, EventArgs e)
 {
      await Task.Yield(); // Make us async right away

      var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later

      await UseDataAsync(data);
 }

~없이Task.Yield()호출 할 때, 메서드는 동 기적으로 첫 번째 호출까지 계속 실행됩니다.await.


  • 여기에 뭔가 잘못 해석하고있는 것 같습니다. 만약await Task.Yield()메소드를 비동기로 강제 실행하는 이유는 무엇입니까? 비동기 코드? 무거운 동기화 방법을 상상해보십시오. 비동기로 만들려면 다음을 추가하십시오.asyncawait Task.Yield()처음에는 마술처럼 비동기가 될까요? 그것은 거의 모든 동기화 코드를Task.Run()그리고 가짜 비동기 메서드를 만듭니다. - Krumelur
  • @Krumelur 큰 차이가 있습니다. 내 예를보세요. 당신이Task.Run그것을 구현하기 위해,ExecuteFooOnUIThreadUI 스레드가 아니라 스레드 풀에서 실행됩니다. 와await Task.Yield(), 후속 코드가 현재 컨텍스트에서 실행되는 방식으로 비동기 적으로 강제 실행됩니다 (이후 시점). 일반적으로하는 일이 아니지만 다소 이상한 이유로 필요한 경우 옵션이 있다는 것이 좋습니다. - Reed Copsey
  • 한 가지 더 질문 : ifExecuteFooOnUIThread()매우 오래 실행되었지만 오랜 시간 동안 UI 스레드를 차단하여 UI를 응답하지 않게 할 수 있습니다. 맞습니까? - Krumelur
  • @Krumelur 예, 그렇습니다. 즉시로 - 나중에 발생합니다. - Reed Copsey
  • 이 답변은 기술적으로는 정확하지만 "나머지 코드는 나중에 실행하게됩니다"라는 문구는 너무 추상적이어서 오도 할 수 있습니다. Task.Yield () 이후의 코드 실행 일정은 구체적인 SynchronisationContext에 크게 의존합니다. 그리고 MSDN 문서에는 "대부분의 UI 환경에서 UI 스레드에있는 동기화 컨텍스트는 종종 입력 및 렌더링 작업보다 높은 컨텍스트에 게시 된 작업의 우선 순위를 결정합니다. 이런 이유로 Task.Yield ()를 기다리지 마십시오. UI를 응답 성있게 유지합니다. " - Vitaliy Tsvayer

26

내부적으로,await Task.Yield()현재 동기화 컨텍스트 또는 임의의 풀 스레드에서 연속을 단순히 대기열에 넣습니다. ifSynchronizationContext.Current~이다.null.

그것은효율적으로 구현 된커스텀 웨이터로서. 동일한 효과를 생성하는 덜 효율적인 코드는 다음과 같이 간단 할 수 있습니다.

var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
    sc.Post(_ => tcs.SetResult(true), null);
else
    ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;

Task.Yield()이상한 실행 흐름 변경에 대한 바로 가기로 사용할 수 있습니다. 예 :

async Task DoDialogAsync()
{
    var dialog = new Form();

    Func<Task> showAsync = async () => 
    {
        await Task.Yield();
        dialog.ShowDialog();
    }

    var dialogTask = showAsync();
    await Task.Yield();

    // now we're on the dialog's nested message loop started by dialog.ShowDialog 
    MessageBox.Show("The dialog is visible, click OK to close");
    dialog.Close();

    await dialogTask;
    // we're back to the main message loop  
}

즉, 나는 어떤 경우에 대해서도 생각할 수 없다.Task.Yield()대체 할 수 없다.Task.Factory.StartNew적절한 작업 스케줄러.

참조 :


-3

Task.Yield()비동기 메소드의 모의 구현에 사용될 수 있습니다.


연결된 질문


관련된 질문

최근 질문