2

まず第一に、私が実装する必要があるものは何もありません。より経験豊富な誰かが、スレッドはやや重い構造であるため、非同期実行は必ずしも新しいスレッドを必要としないと私に言ったので、答えを知る必要があるだけです。

ここで、2 つのメソッドがあるとしましょう -Execute()ExecuteAsync(). Execute()メインスレッドで実行されています。ExecuteAsync()内部から呼び出したいのですExecute()が、実行が完了するたびに気にしません。これは非同期実行の典型的な例ですよね?

BackgroundWorkeror IAsyncResult( )を使用してこれを実行できることはわかっていますが、知る限りDelegate.BeginInvoke()、内部ではセカンダリ CLR スレッド/ThreadPool スレッドが生成されます。

ExecuteAsync()では、2 番目のスレッドの助けを借りずにメソッドを非同期 的に実行することは、どうにかして可能でしょうか?

EDIT :この編集により、シナリオがさらに明確になると思います。呼び出しExecuteAsync()は、 が実行する唯一の (または最後の) タスクではありませんExecute()。メソッドExecute()の実行を気にせずに、独自のタスクを続行する必要があります。ExecuteAsync()

4

3 に答える 3

3

以下は、非同期を使用し、決して複数のスレッドを使用しないプログラムの例です。

public class Foo
{
    private int _value;
    private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    public int Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            var oldTCS = tcs;
            tcs = new TaskCompletionSource<bool>();
            oldTCS.SetResult(true);
        }
    }


    public Task ValueChanged()
    {
        return tcs.Task;
    }
}

private static void Main(string[] args)
{
    Foo foo = new Foo();
    foo.ValueChanged()
        .ContinueWith(t =>
        {
            Console.WriteLine(foo.Value);
        }, TaskContinuationOptions.ExecuteSynchronously);

    foo.Value = 5;
}

Task返却元は、次に変更されたValueChangedときに完了しValueます。クラスのユーザーは、Foo返されたタスクを取得し、まだ発生していない操作に基づいてそのタスクで実行する継続を結び付けることができます。その後、将来のある時点で の値fooが変更され、継続が実行されます。foo オブジェクトは、 にはまったく知られていない他の関数に渡される可能性があることに注意してくださいMain

Taskを作成したり、継続を実行したりするために、新しいスレッドは必要ありません。

より実用的な別の例を次に示します。

Taskフォームを受け取り、そのフォームが次に閉じられたときに示すものを返すこの単純な (拡張) メソッドから始めます。

public static class FormExtensions
{
    public static Task WhenClosed(this Form form)
    {
        var tcs = new TaskCompletionSource<bool>();
        form.FormClosed += (sender, args) => tcs.SetResult(true);
        return tcs.Task;
    }
}

これで、これをフォームの 1 つに含めることができます。

private async void button1_Click(object sender, EventArgs args)
{
    Form2 otherForm = new Form2();
    otherForm.Show();

    await otherForm.WhenClosed();

    //take some data from that form and display it on this form:
    textBox1.Text = otherForm.Name;
}

別のフォームを作成して表示しても、新しいスレッドが作成されることはありません。このフォームと新しいフォームはどちらも、作成および変更する 1 つの UI スレッドを完全に使用します。

Task返された fromの作成ではWhenClosed、新しいスレッドを作成する必要はまったくありません。

待機Task中は、新しいスレッドは作成されません。現在のメソッドは終了し、UI スレッドはメッセージの処理に戻ります。ある時点で、同じ UI スレッドが何かを実行し、2 番目のフォームが閉じられます。これにより、タスクの実行が継続され、テキスト ボックスのテキストを設定するボタン クリック ハンドラーに戻ります。

これはすべてUI スレッドで完全に行われ、他のスレッドは作成されていません。それでも、UI スレッドをブロックせずに、実行時間の長い操作 (ユーザーが 2 番目のフォームに情報を入力してから閉じる) が完了するのを (実際には待機せずに) 「待機」しただけなので、メイン フォームの応答性を維持できます。

于 2013-01-23T19:03:17.457 に答える
1

コルーチンは、単一の物理スレッドを使用して複数の論理スレッドを実装する一般的な方法です。古いオペレーティング システムでは、この概念およびその他の関連する概念を使用して、協調型マルチタスクを実装していました。

このコンテキストでは、継続渡しスタイルにも興味があるかもしれません。Eric Lippertは、まさにこのトピックに関する優れたブログ シリーズ ( Part 1Part 2Part 3Part 4Part 5 ) を持っています。

于 2013-01-23T18:54:35.523 に答える
1

では、2 番目のスレッドの助けを借りずにメソッド ExecuteAsync() を非同期的に実行することはなんとか可能でしょうか?

一部のメソッドは、新しいスレッドを使用せずに非同期で実行できます。これは、たとえば、signalを使用した非同期 I/Oを介して実行できます。フレームワークの新しい Async メソッドのほとんどは、スレッドではなく、可能な限り .NET 4.5 非同期 IO に追加されました。

これが、非同期 == 新しいスレッドであると想定しないことが良い考えである理由です。非同期はスレッド化を使用して実装できますが、常にこの方法で実装されるとは限りません。非同期操作は、(できれば) ブロックせず、将来のある時点で完了する操作と考えたほうがよいでしょう。

于 2013-01-23T18:51:21.593 に答える