Post()またはSendAsync()によるアイテムの送信の違いについて混乱しています。私の理解では、すべての場合において、アイテムがデータブロックの入力バッファーに到達すると、制御は呼び出しコンテキストに戻ります。では、なぜSendAsyncが必要になるのでしょうか。私の仮定が正しくない場合は、反対に、データブロックを使用するという考え全体が同時の非同期環境を確立することであるのに、なぜPost()を使用するのでしょうか。
もちろん、私はPost()がブール値を返すのに対し、SendAsyncは待機可能なブール値のタスクを返すという点で技術的に違いを理解しています。しかし、それはどんな意味を持っていますか? bool(アイテムがデータブロックのキューに配置されたかどうかの確認です)の返送が遅れるのはいつですか?私は非同期/待機同時実行フレームワークの一般的な考え方を理解していますが、ここではあまり意味がありません。渡されたアイテムに対して行われた結果のブール値以外は、呼び出し元に返されることはなく、代わりに「アウトキュー」になり、リンクされたデータブロックに転送されるか、破棄されます。
また、アイテムを送信する場合、2つの方法の間にパフォーマンスの違いはありますか?
違いを確認するには、ブロックがメッセージを延期する状況が必要です。この場合、Post
はfalse
をすぐに返しますが、SendAsync
はTask
を返します。これは、ブロックがメッセージの処理方法を決定したときに完了します。 。 Task
は、メッセージが受け入れられる場合はtrue
結果を受け取り、受け入れられない場合はfalse
結果を受け取ります。
延期の状況の一例は、貪欲でない参加です。より簡単な例は、BoundedCapacity
を設定する場合です。
[TestMethod]
public void Post_WhenNotFull_ReturnsTrue()
{
var block = new BufferBlock<int>(new DataflowBlockOptions {BoundedCapacity = 1});
var result = block.Post(13);
Assert.IsTrue(result);
}
[TestMethod]
public void Post_WhenFull_ReturnsFalse()
{
var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
block.Post(13);
var result = block.Post(13);
Assert.IsFalse(result);
}
[TestMethod]
public void SendAsync_WhenNotFull_ReturnsCompleteTask()
{
// This is an implementation detail; technically, SendAsync could return a task that would complete "quickly" instead of already being completed.
var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
var result = block.SendAsync(13);
Assert.IsTrue(result.IsCompleted);
}
[TestMethod]
public void SendAsync_WhenFull_ReturnsIncompleteTask()
{
var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
block.Post(13);
var result = block.SendAsync(13);
Assert.IsFalse(result.IsCompleted);
}
[TestMethod]
public async Task SendAsync_BecomesNotFull_CompletesTaskWithTrueResult()
{
var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
block.Post(13);
var task = block.SendAsync(13);
block.Receive();
var result = await task;
Assert.IsTrue(result);
}
[TestMethod]
public async Task SendAsync_BecomesDecliningPermanently_CompletesTaskWithFalseResult()
{
var block = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
block.Post(13);
var task = block.SendAsync(13);
block.Complete();
var result = await task;
Assert.IsFalse(result);
}
ドキュメントにより、IMOはこれをかなり明確にします。特に、 Post
の場合:
このメソッドは、ターゲットブロックがアイテムを受け入れるか拒否するかを決定すると戻りますが、ターゲットブロックの特別なセマンティクスによって別段の指示がない限り、アイテムが実際に処理されるのを待ちません。
そして:
提供されたメッセージの延期をサポートするターゲットブロック、または
Post
の実装でより多くの処理を実行する可能性のあるブロックの場合、SendAsync
を使用することを検討してください。後でSendAsync
が戻った後にそれを消費します。
言い換えると、両方とも処理メッセージに関して非同期ですが、SendAsync
を使用すると、ターゲットブロックで承諾メッセージを非同期にするかどうかを決定できます。 。
SendAsync
は一般に「より非同期な」アプローチであり、おそらく一般的に推奨されるアプローチのようです。 ではないはっきりしているのは、両方が必要な理由です。確かに、Post
はSendAsync
を使用して結果を待つのとほぼ同じように聞こえるためです。コメントで述べたように、isには大きな違いが1つあります。バッファがいっぱいの場合、Post
はすぐに拒否しますが、SendAsync
は拒否しません。