8

Begin/End メソッドを記述する必要なく非同期メソッドを使用できるバージョン 4.5 の async CTP を試しています。

私の最初のプローブは、void を返す非同期メソッドを実行することです。いくつかの例を見て、次のことを行います。

private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("click button: " + System.DateTime.Now);
    method01Async();
    UpdateTxtLog("after ethod01Async: " + System.DateTime.Now);
}

private async void method01Async()
{
    await TaskEx.Run(() =>
    {
        UpdateTxtLog("Enter method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("exit method01Async: " + System.DateTime.Now);
    });
}

私の WPF プロジェクトには、結果を表示する textBox と、非同期メソッドを実行するボタンがあります。

async メソッドでは、メソッドが async であるため必要な await を使用し、TasEx.Run を使用して、コードを実行する新しいスレッドを作成します。

私の疑問はこの点にあります。void を返す非同期メソッドを作成する方法のいくつかの例では、この方法 (Task.Run または TaskEx.Run) を使用しています。

私が間違っていなければ、Task.Run はメソッドを実行する新しいスレッドを作成します。次に、タスクで新しいスレッドを作成し、メインスレッドをブロックせずに、必要なものを取得する場合、なぜ非同期メソッドを使用するのですか?

また、非同期メソッドが共有変数にアクセスする場合は、同時実行性に注意する必要がありますよね? したがって、少なくともこの場合、非同期メソッドを使用する利点はわかりません。

実際、async も await も使用せずに同じコードを使用すると、結果は同じで、メイン プログラムはブロックされず、すべて期待どおりに動作します。メソッドは次のとおりです。

private void method01Async()
{
    TaskEx.Run(() =>
    {
        UpdateTxtLog("Enter method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("Exit method01Async: " + System.DateTime.Now);
    });
}

私の質問は、これはメソッドが void を返すときに async を使用する正しい方法ですか?

4

2 に答える 2

4

私が間違っていなければ、Task.Run はメソッドを実行する新しいスレッドを作成します。

ではない正確に。Task.Run()UIスレッドとは異なるスレッドでコードを実行します(少なくともデフォルトでTaskScheduler)。ただし、ほとんどの場合、実際には新しいスレッドを作成ThreadPoolするのではなく、既存のスレッドを.

次に、タスクで新しいスレッドを作成し、メインスレッドをブロックせずに、必要なものを取得する場合、なぜ非同期メソッドを使用するのですか?

UI アプリケーションのコンテキストでの のポイントは、非同期操作の完了asyncに UI スレッドでコードを簡単に実行できるようにすることです。

したがって、method01Async「待機可能」にすると、つまり、次のように返されTaskます。

private async Task method01Async()
{
    await Task.Run(/* whatever */);
}

btnAsync01_Click`async にすると、メソッドからそれを待つことができます。

private async void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("click button: " + System.DateTime.Now);
    await method01Async();
    UpdateTxtLog("after method01Async: " + System.DateTime.Now);
}

Taskこのように、メソッドの最後の行は、 inの実行が終了した後にのみmethod01Async実行されます。そして、UI スレッドで実行されます。

ContinueWith().Net 4.0 では、 andを使用して同様の効果を得ることができましたDispatcher.Invoke()

private void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("click button: " + System.DateTime.Now);
    method01Async().ContinueWith(() =>
        Dispatcher.Invoke(
            new Action(() =>
                UpdateTxtLog("after method01Async: " + System.DateTime.Now)));
}

これははるかに厄介で読みにくいことに同意するでしょう。

また、非同期メソッドが共有変数にアクセスする場合は、同時実行性に注意する必要がありますよね?

はい、その通りです。

実際、async も await も使用せずに同じコードを使用すると、結果は同じで、メイン プログラムはブロックされず、すべて期待どおりに動作します。

結果は確かに、あなたのコードが行うべきだと思っていたものではありません。の最後の行はbtnAsync01_Click「method01Async の後」に実行されますTaskが、そのメソッドで開始されたメソッドが終了するまで待機しません。


async補足として、 で使用する必要はありませんmethod01Async。を直接返すTask(または返さない場合は返さないvoid) と、同じように動作します。

private Task method01Async()
{
    return Task.Run(/* whatever */);
}
于 2012-04-06T14:34:30.867 に答える
1

元の呼び出しを待っていないため、どちらの場合も実際には非同期を使用していません。これがあなたがそれをするべき方法です:

private async void btnAsync01_Click(object sender, RoutedEventArgs e)
{
    UpdateTxtLog("click button: " + System.DateTime.Now);
    await method01Async();
    UpdateTxtLog("after ethod01Async: " + System.DateTime.Now);
}

private async Task method01Async()
{
    return await TaskEx.Run(() =>
    {
        UpdateTxtLog("Enter method01Async: " + System.DateTime.Now);
        Thread.Sleep(10000);
        UpdateTxtLog("exit method01Async: " + System.DateTime.Now);
    });
}

これに変更すると(重要な部分はawait method01Async()ボタンクリックイベントにあり、終了後にジャンプして戻ります。「after ethod01Async:」テキストログには、「exitmethod01Async」ログと同様に10秒の遅延が表示されます。method01Asyncメソッドで。

于 2012-04-06T12:53:19.883 に答える