6

私は過去 2 日間で c# async メソッドについて読んでいましたが、スレッドとは異なり(threadpool.queueuserworkitem())、async メソッドへの呼び出しはすぐには返されず、呼び出されたメソッドが await または complete(or exception) に達したときにのみ返されます。 )

次の例を参照してください。

public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("http://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
} 

私が収集したものから、上記のコードでAccessTheWebAsync()は、同期的に呼び出されます(つまり、制御が呼び出されてもすぐには戻りません)。ただし、「THREE」という名前の行では、ランタイムが制御を返します。

私の質問は次のとおりです。

  1. ランタイムは、スレッドプールをいつ使用するか、または呼び出し元のスレッドでいつタスクを実行するかをどのように決定しますか? (つまり、制御を戻さずにコードを実行する)

  2. 上記のコードのどの時点で、新しいスレッド (またはスレッド プール) が使用されますか?

  3. 無数の反復でループを実行するなど、計算集約的な何かを行った場合AccessTheWebAsync()、制御はループが完了したときにのみ呼び出し元に戻ります。そうですか?

  4. 非同期関数では、コントロールをすぐに返し、バックグラウンド スレッドなどで作業を続行する方法はありますか? (threadpool.queueuserworkitem() を呼び出した場合と同様)

  5. await を使用せずに async メソッドを呼び出すことは (可能であると仮定して)、async 以外のメソッドを呼び出すことと同じですか?

4

2 に答える 2

5

await最初に重要なこと: ランタイムは、待機するタスクがまだ完了していない場合にのみ呼び出し元に戻ります。

質問 1: ここで MSDN を引用します。

async および await キーワードによって、追加のスレッドが作成されることはありません。非同期メソッドは独自のスレッドで実行されないため、非同期メソッドはマルチスレッドを必要としません。

ソース

質問 2: の実装にあるかもしれGetStringAsyncませんが、それはわかりませんし、知る必要もありません。GetStringAsyncスレッドをブロックせずに結果が得られることを知っていれば十分です。

質問 3: ループがawaitキーワードの前にある場合は、はい。

質問 4: 前と同じ段落からの引用:

Task.Run を使用して、CPU バウンドの作業をバックグラウンド スレッドに移動できます。

asyncこれにはandawaitキーワードは必要ありません。例:

private Task<int> DoSomethingAsync()
{
    return Task.Run(() =>
    {
        // Do CPU heavy calculation here. It will be executed in the thread pool.
        return 1 + 1;
    });
}

質問5:もう一度引用します

通常、非同期メソッドには await 演算子が 1 つ以上含まれていますが、await 式がなくてもコンパイラ エラーは発生しません。非同期メソッドが中断ポイントをマークするために await 演算子を使用しない場合、メソッドは async 修飾子に関係なく、同期メソッドと同じように実行されます。コンパイラは、そのようなメソッドに対して警告を発行します。

ソース(前と同じページ、別のセクション)

于 2013-06-07T09:01:43.537 に答える
3

ランタイムは、スレッドプールをいつ使用するか、または呼び出し元のスレッドでいつタスクを実行するかをどのように決定しますか?

同期コンテキストがあり、コンテキストを続行しないことを明示的に指定しない場合 ( などを使用してawait task.ConfigureAwait(false))、メソッドはキャプチャされたコンテキストで再開されます。UI アプリケーションでは、メソッドが UI スレッドから呼び出されると仮定すると、そのコンテキストは UI スレッドです。

上記のコードのどの時点で、新しいスレッド (またはスレッド プール) が使用されますか?

どこにもない。特に指定しない限り (上記を参照)、awaitキャプチャされたコンテキスト (この場合は UI スレッド) で再開します。

無数の反復でループを実行するなど、計算集約的な何かを行った場合AccessTheWebAsync()、制御はループが完了したときにのみ呼び出し元に戻ります。そうですか?

はい、ループが最初の「非同期」の前にあったと仮定しますawait。( edが既に完了しているawait場合は、「同期」することもできます。)awaitTask

非同期関数では、コントロールをすぐに返し、バックグラウンド スレッドなどで作業を続行する方法はありますか?

そのために使うべきTask.Run()です。

await を使用せずに async メソッドを呼び出すことは (可能であると仮定して)、async 以外のメソッドを呼び出すことと同じですか?

その可能性があり、コンパイラは、メソッドが完全に同期的に実行されることを警告します。

于 2013-06-07T10:58:26.327 に答える