void async 메소드 대기


155

void async메소드가 작업을 완료하기를 기다리는 방법은 무엇입니까?

예를 들어 다음과 같은 기능이 있습니다.

async void LoadBlahBlah()
{
    await blah();
    ...
}

이제 다른 곳에서 계속하기 전에 모든 것이로드되었는지 확인하고 싶습니다.

답변:


234

가장 좋은 방법은 기능이 async void불인 경우에만 기능을 표시 하고 방법을 잊어 버리고 기다리는 경우에는로 표시해야합니다 async Task.

만약 당신이 여전히 기다리고 싶다면, 그렇게 포장하십시오 await Task.Run(() => blah())


blah는 분명히 작업을 반환하고 있으며 비동기 서명은 왜 기다리지 않고 호출합니까? VS조차도 그것에 대해 경고합니다.
batmaci

8
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
테마 필드

1
await Task.Run(() => blah())오해의 소지가 있습니다. 이것은 async function의 완료를 기다리지 blah않고 작업의 (사소한) 생성을 기다리며 blah()완료 직전에 계속 됩니다.
Jonathan Lidbeck

@JonathanLidbeck 문은 "blah가 잘못되기 직전에 계속됩니다."await Task.Run (() => Thread.Sleep (10_000)) "를 시도하십시오. 다음 줄을 실행하기 전에 작업이 10 초 이상 기다립니다
Rohit Sharma

@RohitSharma, 귀하의 예에는 맞지만 Thread.Sleep비동기식은 아닙니다. 이 질문은 async void기능 대기에 관한 것입니다.async void blah() { Task.Delay(10000); }
Jonathan Lidbeck


27

가장 좋은 해결책은를 사용하는 것 async Task입니다. async void몇 가지 이유 때문에 작곡가 는 피해야 합니다.

메소드 가 리턴 될 수없는 경우 Task(예 : 이벤트 핸들러 인 경우) SemaphoreSlim종료하려고 할 때 메소드 신호를 갖는 데 사용할 수 있습니다 . 이것을 finally블록 으로하는 것을 고려하십시오 .


1

AutoResetEvent를 수행하고 함수를 호출 한 다음 AutoResetEvent를 기다린 다음 완료되었음을 알면 async void 안에 설정하십시오.

당신은 또한 당신의 공허 비동기에서 반환 작업을 기다릴 수 있습니다


1

실제로 수동으로 아무것도 할 필요가 없으며 await키워드 blah()는 반환 될 때까지 함수 실행을 일시 중지 합니다.

private async void SomeFunction()
{
     var x = await LoadBlahBlah(); <- Function is not paused
     //rest of the code get's executed even if LoadBlahBlah() is still executing
}

private async Task<T> LoadBlahBlah()
{
     await DoStuff();  <- function is paused
     await DoMoreStuff();
}

T객체 blah()반환 유형

당신은 정말 할 수 기능은 그렇게 할 수 없다awaitvoidLoadBlahBlah()void


나는 기다릴 싶지 LoadBlahBlah(),하지 마칩니다blah()
MBZ

10
불행히도 비동기 void 메소드는 실행을 일시 중지하지 않습니다 (비동기 태스크 메소드와 달리)
ghord

-1

나는 이것이 오래된 질문이라는 것을 알고 있지만 이것은 여전히 ​​겪고있는 문제이지만 여전히 비동기 무효 서명 방법에서 async / await를 사용할 때이를 올바르게 수행하는 명확한 해결책은 없습니다.

그러나 void 메서드 내에서 .Wait ()이 제대로 작동한다는 것을 알았습니다.

async void와 void는 동일한 서명을 가지므로 다음을 수행해야 할 수도 있습니다.

void LoadBlahBlah()
{
    blah().Wait(); //this blocks
}

혼란스럽게도 충분한 비동기 / 대기는 다음 코드에서 차단되지 않습니다.

async void LoadBlahBlah()
{
    await blah(); //this does not block
}

코드를 디 컴파일 할 때 async void는 내부 작업 (비동기 작업과 동일)을 생성하지만 서명은 내부 작업을 반환하도록 지원하지 않기 때문에

이것은 내부적으로 비동기 void 메소드가 내부적으로 비동기 메소드를 "대기"할 수 있음을 의미합니다. 내부 작업이 언제 완료되는지 외부에서 알 수 없습니다.

따라서 제 결론은 비동기 void가 의도 한대로 작동하고 내부 작업의 피드백이 필요한 경우 대신 비동기 작업 서명을 사용해야한다는 것입니다.

잘만되면 나의 학대는 답을 찾는 사람에게도 의미가있다.

편집 : 나는 예제 코드를 만들고 실제로 무슨 일이 일어나고 있는지 확인하기 위해 디 컴파일했다.

static async void Test()
{
    await Task.Delay(5000);
}

static async Task TestAsync()
{
    await Task.Delay(5000);
}

로 바뀝니다 (편집 : 본문 코드는 여기가 아니라 상태 머신에 있지만 상태 머신은 기본적으로 동일하므로 추가하지 않아도됩니다)

private static void Test()
{
    <Test>d__1 stateMachine = new <Test>d__1();
    stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
    <TestAsync>d__2 stateMachine = new <TestAsync>d__2();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

AsyncVoidMethodBuilder 또는 AsyncTaskMethodBuilder는 실제로 Start 메서드에 차단할 힌트를주는 코드가 없으며 시작된 후에는 항상 비동기 적으로 실행됩니다.

반환 작업이 없으면 의미가 완료되었는지 확인할 방법이 없습니다.

예상대로 비동기 실행 작업 만 시작한 다음 코드에서 계속됩니다. 비동기 작업은 먼저 작업을 시작한 다음 반환합니다.

그래서 내 대답은 비동기 void를 절대 사용하지 않는 것 같습니다. 작업이 언제 완료되는지 알아야 할 경우 비동기 작업의 목적입니다.

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