8

私は多くのネットワーク接続の複雑な調停者であるライブラリを持っています。プライマリオブジェクトの各メソッドはデリゲートを取ります。デリゲートは、ネットワークが特定の要求に応答したときに呼び出されます。

新しい.NET4.5の「async/await」パターンを使用するようにライブラリを変換したいと思います。これには、「タスク」オブジェクトを返す必要があります。これにより、呼び出しの非同期部分が完了したことがユーザーに通知されます。このオブジェクトを作成するには、タスクが表す関数が必要です-私の理解では、これは本質的に軽量のスレッドです。

これは私のライブラリの設計に実際には適合しません。タスクをイベントのように動作させ、関数を表すのではなく、リクエストが完了したことをユーザーに直接通知したいと思います。これは可能ですか?このように「async/await」パターンを悪用することは避けなければなりませんか?

私がこれをうまく表現しているかどうかはわかりませんが、私の意味を理解していただければ幸いです。助けてくれてありがとう。

4

2 に答える 2

15

私の理解する限り、それは本質的に軽量のスレッドです。

いいえ、それは本当ではありません。特定の状況下では、私は真実である可能性Taskがありますが、それはの1つの使用法にすぎません。スレッドをデリゲートに渡して実行させることで、スレッドを開始できます(通常は非同期、場合によっては同期、デフォルトではスレッドプールを使用)。

スレッドを使用する別の方法は、を使用することTaskCompletionSourceです。これを行うと、タスクは(潜在的に)スレッドを作成したり、スレッドプールを使用したりすることはありません。このモデルの一般的な使用法の1つは、イベントベースのAPIをタスクベースのAPIに変換することです。

それが一般的な例であるという理由だけで、私たちが持っているものが閉じられTaskたときに完了するものが欲しいと仮定しましょう。そのイベントが発生したときに発生するイベントFromがすでにあります。FormClosed

public static Task WhenClosed(this Form form)
{
    var tcs = new TaskCompletionSource<object>();

    form.FormClosing += (_, args) =>
    {
        tcs.SetResult(null);
    };

    return tcs.Task;
}

を作成しTaskCompletionSource、問題のイベントにハンドラーを追加します。そのハンドラーで、タスクの完了を通知し、呼び出し元に戻るためのをTaskCompletionSource提供します。TaskこれTaskにより、新しいスレッドが作成されることはなく、スレッドプールなども使用されません。

まったく非同期に見えるこの構成を使用して、タスク/イベントベースのモデルを作成できますが、すべての作業を実行するために単一のスレッド(UIスレッド)のみを使用します。

Task一般に、関数の実行以外の何かを表すを必要とするときはいつでも、を使用することを検討する必要がありますTaskCompletionSourceWhenAllこれは、、、などの既存のTPLメソッドのいずれかを使用する場合を除いて、通常、問題にアプローチするための適切な概念的な方法ですWhenAny

このように「async/await」パターンを悪用することは避けなければなりませんか?

いいえ、虐待ではないので。Taskこれは、構成概念と同様に完全に適切な使用法ですasync/await。たとえば、上記のヘルパーメソッドを使用して記述できるコードについて考えてみます。

private async void button1_Click(object sender, EventArgs e)
{
    Form2 popup = new Form2();
    this.Hide();
    popup.Show();
    await popup.WhenClosed();
    this.Show();
}

このコードは、読み取りと同じように機能するようになりました。新しいフォームを作成し、自分自身を非表示にし、ポップアップを表示し、ポップアップが閉じるまで待ってから、もう一度自分自身を表示します。ただし、これはブロック待機ではないため、UIスレッドはブロックされません。また、イベントを気にする必要もありません。ハンドラーの追加、複数のコンテキストの処理。ロジックを動かしたり、そのいずれかを動かしたりします。(それはすべて起こります、それは私たちから隠されているだけです。)

于 2012-11-21T15:11:39.813 に答える
5

新しい.NET4.5の「async/await」パターンを使用するようにライブラリを変換したいと思います。これには、「タスク」オブジェクトを返す必要があります。これにより、呼び出しの非同期部分が完了したことがユーザーに通知されます。

まあ、実際にはそうではありません-待機可能なパターンを実装するものなら何でも返すことができます-しかし、Taskこれを行う最も簡単な方法です。

これは私のライブラリの設計に実際には適合しません。タスクをイベントのように動作させ、関数を表すのではなく、リクエストが完了したことをユーザーに直接通知したいと思います。

Task.ContinueWithタスクが完了したときに実行する「ハンドラー」として機能するように呼び出すことができます。確かに、それは内部で行うことTaskAwaiterです。

あなたの質問は正直に言うとそれほど明確ではありませんが、本当にTask好きなときに強制的に完了できるものを作成したい場合は、あなたが望むだけだと思います- 、またはメソッドをTaskCompletionSource<TResult>呼び出して、適切な種類の完了を示します。(または、バージョンを呼び出すこともできます。)プロパティを使用して、タスクを必要なものに戻します。SetResultSetCanceledSetExceptionTrySet...Task

于 2012-11-21T15:04:58.527 に答える