Как дождаться завершения асинхронного метода?



Я пишу приложение WinForms, которое передает данные на устройство класса USB HID. Мое приложение использует отличную универсальную библиотеку HID v6. 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()


к сожалению, я не очень хорошо знаком с работой новых технологий async/await в .NET 4.5. Я немного читал ранее о ключевом слове await, и это создало у меня впечатление, что вызов GetInputReportViaInterruptTransfer () внутри RequestToGetInputReport () будет ждать (и, возможно, это так?) но это не похоже на вызов RequestToGetInputReport () сам ждет, потому что я, кажется, повторно входя в цикл while почти сразу?



может ли кто-нибудь прояснить поведение, которое я вижу?

1532   4  

4 ответов:

избежать 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();
}

самое главное, чтобы знать о async и await это 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/ и http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx.

лучшим решением для ожидания AsynMethod до завершения задачи является

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

в следующем фрагменте кода показан способ обеспечения завершения ожидаемого метода перед возвращением к вызывающему объекту. Однако я бы не сказал, что это хорошая практика. Пожалуйста, отредактируйте мой ответ с объяснениями, если вы думаете иначе.

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

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

Comments

    Ничего не найдено.