web-dev-qa-db-ja.com

待機/非同期とスレッド化はどのように異なりますか?

私はc#の新しいawait/asyncキーワードに慣れ親しんでいるところですが、理解できないいくつかの側面を見つけました。

  1. 競合状態から始めましょう:

    _Stream s=...
    ...
    for(int i=0;i<100;i++)
    {
        s.WriteAsync(new byte[]{i},0,1);
    }
    _

    これは常に期待どおりに機能しますか(たとえば、13345などではなく、ファイル12345 .....に書き込みます)?

    2つ目は、await演算子が含まれていない場合、async関数は同期的に実行されることです。また、Microsoftのドキュメントによると、非同期関数は常に(BeginInvokeと比較して)呼び出し元スレッドで実行されます。これにより、次の3つの質問が表示されます。

  2. 非同期関数は、呼び出し元関数に解放される前にどれだけ実行されますか?

    _async void MyAsyncFunction()
    {
        Operation1();
        Operation2();
        Operation3();
        ....
        Stream s=...;
        await s.WriteAsync(....);
    }
    _

    私が読んだawait/asyncに関する記事では、await演算子なしのasync関数が順次実行され、async/awaitがすぐに返されると言われています。しかし、MyAsyncFunctionは常に_await s.WriteAsync_にヒットするため、解放する前にOperation1 ... Operation3を実行する可能性があるというのが私を悩ませています。

  3. このような非同期関数で_Thread.Sleep_を使用するとどうなりますか?

    _async void DoStuff()
    {
        Stream s=...;
        ...
        await s.WriteAsync(....);
        Thread.Sleep(10000);
        ....
    }
    _

    Thread.Sleepは、それが実行されるスレッド全体をブロックしますか、それとも非同期関数だけをブロックしますか?

  4. 非同期関数の1つでsemaphore.Wait()を使用すると、セマフォが他の非同期関数によって解放されることが期待されます。これはスレッドの場合と同じように動作しますか、それともデッドロックを引き起こしますか?

  5. awaitは、非同期関数以外では機能しません。どうして?

23
Arsen Zahray

async intro を読むことをお勧めします。

これは常に期待どおりに機能しますか(たとえば、13345などではなく、ファイル12345 .....に書き込みます)?

いいえ。awaitへの呼び出しをWriteAsyncする必要があります。

非同期関数は、呼び出し元関数に解放される前にどれだけ実行されますか?

それまでは、まだ完了していない操作がawaitsされます。

Thread.Sleepは、それが実行されるスレッド全体をブロックしますか、それとも非同期関数だけをブロックしますか?

Thread.Sleep-および他のすべてのブロックメソッド-asyncメソッドとそれを実行しているスレッドをブロックします。

一般的なルールとして、asyncメソッド内でanyブロックメソッドを使用しないでください。

非同期関数の1つでsemaphore.Wait()を使用すると、セマフォが他の非同期関数によって解放されることが期待されます。これはスレッドの場合と同じように動作しますか、それともデッドロックを引き起こしますか?

それは完全にあなたのコンテキストに依存します。 Waitはブロッキングメソッドであるため、「その他」のasyncメソッドがブロックされたメソッドが保持するコンテキストを必要とする場合、デッドロックが発生します。

SemaphoreSlimasyncに対応していることに注意してください。 WaitAsyncの代わりにWaitを使用できます。

awaitは非同期関数以外では機能しません。どうして?

asyncキーワードはawaitキーワードを有効にするためです。これは、C#言語に対する新しいキーワードの影響を最小限に抑え、コードを読みやすくするために行われました。

16
Stephen Cleary

awaitoperatorに関する質問への回答は、次の Eric Lippertによる投稿 で見つけることができます。

「await」演算子…は、「このメソッドは現在、非同期操作が戻るまで現在のスレッドをブロックする」という意味ではありません。これは、非同期操作を同期操作に戻すことです。これは、まさに回避しようとしていることです。むしろ、それはその逆です。これは、「待機中のタスクがまだ完了していない場合は、そのタスクの継続としてこのメ​​ソッドの残りの部分にサインアップし、すぐに呼び出し元に戻ります。タスクは完了時に継続を呼び出します。 -エリック・リペルト

15
Adrian Ciura

要するに、答えは「非常に」のようです。以下はすべての質問に答えるわけではありませんが、一般的に十分なユースケースに当てはまると思います。ネットワークの代わりにストリームを考えてくださいIO彼らが参照している.

重複したネットワークIOの場合、IO完了ポートが使用され、コールバックはハードウェアの割り込みによってトリガーされます。

つまり、完了を「待つ」間、スレッドは消費されません。 [...]

1つのスレッドですべてを実行できます。 [...]ただし、プラットフォーム、「待機者」の実装、および使用されている同期コンテキストによって異なります。

http://social.msdn.Microsoft.com/Forums/en-US/async/thread/a46c8a54-f8d4-4fa9-8746-64d6a3a7540d/

0
Montagist