9

をいつ使用するかを理解しようとしていますTaskEx.Run。以下に書いた、同じ結果を生成する 2 つのコード サンプルを提供しました。私が見落としているのは、私がTask.RunEx アプローチを取る理由TaskEx.RunExです。正当な理由があると確信しており、誰かが私を記入してくれることを望んでいました.

async Task DoWork(CancellationToken cancelToken, IProgress<string> progress)
{
    int i = 0;
    TaskEx.RunEx(async () =>
        {
            while (!cancelToken.IsCancellationRequested)
            {
                progress.Report(i++.ToString());
                await TaskEx.Delay(1, cancelToken);
            }
        }, cancelToken);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
    if (button.Content.ToString() == "Start")
    {
        button.Content = "Stop";
        cts.Dispose();
        cts = new CancellationTokenSource();
        listBox.Items.Clear();
        IProgress<string> progress = new Progress<string>(s => 
        {
            listBox.Items.Add(s); 
            listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
        });
        DoWork(cts.Token, progress);
    }
    else
    {
        button.Content = "Start";
        cts.Cancel();
    }
}

私はそのように同じ結果を達成することができます

  async Task DoWork(CancellationToken cancelToken)
    {
        int i = 0;
        while (!cancelToken.IsCancellationRequested)
        {
            listBox.Items.Add(i++);
            listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
            await TaskEx.Delay(100, cancelToken);

        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (button.Content.ToString() == "Start")
        {
            button.Content = "Stop";
            cts.Dispose();
            cts = new CancellationTokenSource();
            listBox.Items.Clear();
            DoWork(cts.Token);
        }
        else
        {
            button.Content = "Start";
            cts.Cancel();
        }
    }
4

3 に答える 3

13

スレッド プール コンテキストで同期コードを実行する場合に使用TaskEx.Runします。

スレッド プール コンテキストで非同期コードを実行する場合に使用TaskEx.RunExします。

Stephen Toub は、動作の違いに関連する 2 つのブログ投稿を行っています。

これは、タスクを作成するためのいくつかのオプションの 1 つにすぎません。Run/を使用する必要がない場合は、使用しないRunExでください。シンプルなasync方法を使用し、バックグラウンドで何かを実行する必要がある場合にのみRun/を使用してください。RunEx

于 2012-02-17T20:27:49.930 に答える
1

2 つのメソッドの違いDoWork()は、最初のメソッド (を使用するTaskEx.RunEx()) がまったく非同期ではないことです。これは完全に同期的に実行され、別のスレッドで別のタスクを開始し、すぐに completed を返しますTaskawaitそのタスクをed またはWait()ed した場合、内部タスクが完了するまで待機しません。

于 2012-02-17T22:50:59.340 に答える
0

Task.Run は、私が理解しているように、ほとんどのシナリオで新しいスレッドを生成します。

メソッドを非同期としてマークし、awaiter を使用するという理由だけで、これは (必然的に) 新しいスレッドが作成されることを意味するわけではなく、多くの場合、呼び出し元と同じ実行スレッドで完了がスケジュールされることに注意することが重要です。

ここでのトリックは、SchedulingContext に関係しています。マルチスレッド アパートメント用に設定されている場合は、完了をスレッドプール上の実行可能なスレッドに委任します。すべての WPF および WinForms UI コードがそうであるように、シングルスレッド アパートメントにいる場合は、完了のために呼び出し元のスレッドに戻り、コード内で目に見えるスレッド マーシャリングを行うことなく、UI で直接作業を行うことができます。

于 2012-02-17T20:22:51.303 に答える