1

SO 私は最近、ネットの Async CTP について大量の本を読んでいますが、「非同期とは、新しいスレッドを開始することではなく、作業を多重化することです」、「マルチスレッドを使用しない非同期は、 [協調的マルチタスキングと同じ考え方] あるタスクをしばらく実行し、そのタスクが制御を譲ると、そのスレッドで別のタスクをしばらく実行します。

このような発言が純粋に (まあ、ほとんど) 難解で学術的なものなのか、それとも "await" 経由で開始したタスクを UI スレッドで魔法のように実行できるようにする、見落としている言語構造があるのか​​どうかを理解しようとしています。

Eric Lippert は彼のブログで、マルチスレッドなしで Asyncrhony を使用する方法のデモンストレーションとして、次の例を示しています。

async void FrobAll()
{
    for(int i = 0; i < 100; ++i)
    {
        await FrobAsync(i); // somehow get a started task for doing a Frob(i) operation on this thread
    }
} 

さて、ここで私が興味をそそられるのは、「...このスレッドで Frob(i) 操作を実行するための開始済みタスクを取得する」というコメントです。

これはどのように可能ですか?これは主に理論的な発言ですか?これまでのところ、タスクが別のスレッドを必要としないように見える唯一のケース (コードを調べない限り、確かなことはわかりません) は、Task.Delay() のようなもので、これはなくても待機できます。別のスレッドを開始します。しかし、私はそのためのコードを書いていないので、これは特殊なケースだと考えています。

実行時間の長い独自のコードの一部を GUI スレッドからオフロードしたい平均的なユーザーにとって、私たちは主に Task.Run のようなことをして作業をオフロードすることについて話しているのではないでしょうか。スレッド?もしそうなら、なぜ、非同期処理とマルチスレッド処理を混同しないように、このすべての腕が放棄されているのでしょうか?

4

3 に答える 3

2

100% 確実ではありませんが、記事からは、Windows メッセージ (サイズ変更イベント、マウス クリックなど) を の呼び出しの間にインターリーブできるようになっているように思えますFrobAsync。以下にほぼ類似しています。

void FrobAll()
{
    for(int i = 0; i < 100; ++i)
    {
        FrobAsync(i); // somehow get a started task for doing a Frob(i) operation on this thread
        System.Windows.Forms.Application.DoEvents();
    }
}

または多分より正確に:

void FrobAll()
{
    SynchronizationContext.Current.Post(QueueFrob, 0);
} 

void QueueFrob(Object state) {
    var i = (int)state;
    FrobAsync(i);
    if (i == 99) return;
    SynchronizationContext.Current.Post(QueueFrob, i+1);
}

DoEvents各反復間の厄介な呼び出しなし。これが発生する理由は、await の呼び出しが呼び出しをエンキューする Windows メッセージを送信しFrobAsync、Frobbings の間に発生した Windows メッセージを次の Frobbing が開始する前に実行できるようにするためです。

于 2012-08-02T14:35:51.213 に答える
2

/の紹介をasyncawaitご覧ください。

CPU 作業の場合Task.Run、別のスレッドで実行するようなものを使用する必要があります。ただし、CPU の作業ではない作業 (ネットワーク要求、ファイル システム要求、タイマーなど) がたくさんあり、それらのそれぞれは、スレッドを使用Task せずにラップすることができます。

ドライバー レベルでは、すべてが非同期であることを忘れないでください。同期 Win32 API は単なる便利なラッパーです。

于 2012-08-02T14:28:50.240 に答える
1

async/awaitは単に非同期に関するものです。呼び出し側からは、複数のスレッドが使用されているかどうかは問題ではありません。つまり、非同期で何かを実行するだけです。たとえば、IO 完了ポートは非​​同期ですが、マルチスレッド化は行いません (操作の完了はバックグラウンド スレッドで発生しますが、そのスレッドでは「作業」は行われませんでした)。

キーワードからしてawait、「マルチスレッド」は無意味です。非同期操作が行うことは、実装の詳細です。

エリックの例の意味では、そのメソッドは次のように実装できた可能性があります。

return Task.Factory.StartNew(SomeMethod, 
                             TaskScheduler.FromCurrentSynchronizationContext());

SomeMethodこれは、現在キューに入れられているすべての作業が完了したときに、現在のスレッドで呼び出しをキューに入れることを意味します。FrobAsyncこれはinの呼び出し元に対して非同期であり、実行されるFrobAsync前に返される可能性がありますSomeMethod

現在、FrobAsyncマルチスレッドを使用するように実装できた可能性があります。その場合、次のように記述できます。

return Task.Factory.StartNew(SomeMethod);

デフォルトの TaskScheduler が変更されていない場合、これはスレッド プールを使用します。しかし、呼び出し元の観点からは、何も変わっていません。あなたはまだawaitメソッドです。

マルチスレッドの観点から、これはあなたが見るべきものです。Task.StartTask.Run、またはを使用しTask.Factory.StartNewます。

于 2012-08-02T14:47:45.420 に答える