166

USBHIDクラスデバイスにデータを転送するWinFormsアプリケーションを作成しています。私のアプリケーションは、ここにある優れたGenericHIDライブラリ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()

残念ながら、私は.NET4.5の新しいasync/awaitテクノロジーの仕組みにあまり詳しくありません。awaitキーワードについて少し前に読んだところ、RequestToGetInputReport()内のGetInputReportViaInterruptTransfer()の呼び出しは待機する(そしておそらくそうなるのでしょうか?)という印象を与えましたが、RequestToGetInputReport()の呼び出しのようには見えません。ほぼすぐにwhileループに再び入るように見えるので、それ自体が待機していますか?

誰かが私が見ている行動を明確にすることができますか?

4

7 に答える 7

267

asyncandについて知っておくべき最も重要なことawaitは、関連する呼び出しが完了するのを待たawait ないことです。操作が既に完了している場合は操作awaitの結果を直ちに同期的に返すか、完了していない場合はメソッドの残りを実行するために継続をスケジュールし、呼び出し元に制御を返します。非同期操作が完了すると、スケジュールされた完了が実行されます。async

質問のタイトルの特定の質問に対する答えは、適切なメソッドを呼び出してasyncメソッドの戻り値 ( Taskor型である必要があります) をブロックすることです。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 によって公開されているさまざまな非同期メカニズムの非効率的な使用です。

「待機」の回答には、呼び出しの完了を待たないで、これらのキーワードのより詳細な説明がいくつかあります。

一方、保持に関する@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

于 2013-03-01T05:53:52.967 に答える
150

避けてくださいasync voidTaskの代わりにメソッドを返してください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();
}
于 2013-03-01T03:10:27.980 に答える
104

タスクが完了するまで AsynMethod を待機する最適なソリューションは

var result = Task.Run(async() => await yourAsyncMethod()).Result;
于 2017-06-16T00:14:29.770 に答える
-5

次のスニペットは、待機中のメソッドが呼び出し元に戻る前に確実に完了する方法を示しています。ただし、それが良い習慣だとは言えません。そうでない場合は、説明を付けて私の回答を編集してください。

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

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")
于 2016-03-08T21:45:50.607 に答える
-5

実際、これは IAsyncAction を返す関数でより役立つことがわかりました。

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;
于 2019-02-10T21:14:15.100 に答える