USB HIDクラスのデバイスにデータを転送するWinFormsアプリケーションを書いています。私のアプリケーションは、見つけることができる優れたGeneric 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()
残念ながら、私は.NET 4.5の新しいasync/awaitテクノロジの働きについてはあまりよく知らない。 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();
}
async
とawait
について知っておくべき最も重要なことは、await
does n'tが関連付けられた呼び出しの完了を待つことです。 await
が行うことは、操作の結果を即座に同期的に返すことです操作が既に完了している場合、または、完了していない場合は、async
メソッドの残りを実行する継続をスケジュールし、呼び出し元に制御を返します。非同期操作が完了すると、スケジュールされた完了が実行されます。
質問のタイトルにある特定の質問に対する答えは、適切なasync
メソッドを呼び出すことにより、Task
メソッドの戻り値(タイプWait
またはTask<T>
でなければなりません)をブロックすることです。
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
はsynchronous非同期メソッドGetFooAsync
のラッパーです。ただし、このパターンは、非同期操作の実行中にスレッドプールスレッド全体をブロックするため、ほとんどの場合は使用しないでください。これは、APIによって公開されるさまざまな非同期メカニズムの非効率的な使用であり、APIを提供するために多大な努力を払っています。
"await"での答えは、call の完了を待たず、これらのキーワードのより詳細な説明がいくつかあります。
一方、async void
に関する@Stephen Clearyのガイダンスは保持されます。理由のその他の素敵な説明は、 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() => { return await yourAsyncMethod(); }).Result;