[C#] 비동기 메서드가 완료되기를 기다리는 방법은 무엇입니까?

데이터를 USB HID 클래스 장치로 전송하는 WinForms 응용 프로그램을 작성 중입니다. 내 응용 프로그램을 찾을 수있는 우수한 일반 HID 라이브러리 6.0 사용 여기를 . 간단히 말해서, 장치에 데이터를 써야 할 때 이것이 호출되는 코드입니다.

private async void RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        RequestToGetInputReport();
    }
}

코드가 while 루프에서 빠지면 장치에서 일부 데이터를 읽어야합니다. 그러나 장치가 바로 응답 할 수 없으므로 계속 진행하기 전에이 통화가 돌아올 때까지 기다려야합니다. 현재 존재하므로 RequestToGetInputReport ()는 다음과 같이 선언됩니다.

private async void RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

가치가있는 것에 대한 GetInputReportViaInterruptTransfer () 선언은 다음과 같습니다.

internal async Task<int> GetInputReportViaInterruptTransfer()

불행히도, 나는 .NET 4.5의 새로운 비동기 / 대기 기술의 작동에 익숙하지 않습니다. 나는 await 키워드에 대해 조금 읽었고 RequestToGetInputReport () 내부의 GetInputReportViaInterruptTransfer () 호출이 대기 할 것이라는 인상을 받았지만 RequestToGetInputReport () 호출과 같지 않습니다. while 루프를 거의 즉시 다시 입력하기 때문에 자체적으로 기다리고 있습니까?

아무도 내가보고있는 행동을 분명히 할 수 있습니까?



답변

피하십시오 async void. Task대신 메소드를 반환하십시오 void. 그럼 당신은 할 수 await있습니다.

이처럼 :

private async Task RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        await RequestToGetInputReport();
    }
}

private async Task RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}


답변

가장 중요한 것은에 대해 알아야 할 사항 asyncawait그가 await 되지 않습니다 완료 될 때까지 관련 전화 기다립니다. 어떤 await일은 즉시 동 기적으로 작업의 결과를 반환하는 작업이 이미 완료 한 경우 나, 그렇지 않은 경우의 나머지 실행하기 위해 계속 예약 async방법을 다음 호출자에게 컨트롤을 반환 할 수 있습니다. 비동기 작업이 완료되면 예약 완료가 실행됩니다.

질문 제목의 특정 질문에 대한 답변 은 적절한 메소드 를 호출하여 async메소드의 반환 값 ( Task또는 유형이어야 함 )을 차단하는 것입니다 .Task<T>Wait

public static async Task<Foo> GetFooAsync()
{
    // Start asynchronous operation(s) and return associated task.
    ...
}

public static Foo CallGetFooAsyncAndWaitOnResult()
{
    var task = GetFooAsync();
    task.Wait(); // Blocks current thread until GetFooAsync task completes
                 // For pedagogical use only: in general, don't do this!
    var result = task.Result;
    return result;
}

이 코드 스 니펫 CallGetFooAsyncAndWaitOnResult은 비동기 메소드 주위 의 동기 랩퍼 GetFooAsync입니다. 그러나이 패턴은 비동기 작업 중에 전체 스레드 풀 스레드를 차단하므로 대부분 피해야합니다. 이는 API에 노출 된 다양한 비동기 메커니즘을 비효율적으로 사용하여이를 제공하기 위해 많은 노력을 기울입니다.

“await” 의 답변 은 통화완료 될 때까지 기다리지 않습니다 . 이러한 키워드에 대한 자세한 설명이 몇 가지 있습니다.

한편 @Stephen Cleary의 지침은 async void보류입니다. 이유에 대한 다른 좋은 설명은 http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/https://jaylee.org/archive/ 에서 찾을 수 있습니다. 2012 / 07 / 08 / c-sharp-async-tips-and-tricks-part-2-async-void.html


답변

AsynMethod가 작업을 완료 할 때까지 기다리는 가장 좋은 방법은

var result = Task.Run(async() => await yourAsyncMethod()).Result;


답변

다음은 플래그를 사용하는 해결 방법입니다.

//outside your event or method, but inside your class
private bool IsExecuted = false;

private async Task MethodA()
{

//Do Stuff Here

IsExecuted = true;
}

.
.
.

//Inside your event or method

{
await MethodA();

while (!isExecuted) Thread.Sleep(200); // <-------

await MethodB();
}


답변

작업이 완료 될 때까지 대기하기 위해 Wait ()를 넣으십시오.

GetInputReportViaInterruptTransfer().Wait();


답변

다음 스 니펫은 호출자에게 리턴하기 전에 대기중인 메소드가 완료되도록하는 방법을 보여줍니다. 그러나 나는 그것이 좋은 습관이라고 말하지 않을 것입니다. 당신이 다르게 생각한다면 설명과 함께 내 대답을 편집하십시오.

public async Task AnAsyncMethodThatCompletes()
{
    await SomeAsyncMethod();
    DoSomeMoreStuff();
    await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")


답변

실제로 이것은 IAsyncAction을 반환하는 함수에 더 유용하다는 것을 알았습니다.

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;