Поток данных TPL, в чем функциональная разница между Post() и SendAsync()?
Меня смущает разница между отправкой элементов через Post() или SendAsync(). Насколько я понимаю, во всех случаях, когда элемент достигает входного буфера блока данных, управление возвращается в контекст вызова, правильно? Тогда зачем мне нужен SendAsync? Если мое предположение неверно, то мне, наоборот, интересно, почему кто-то когда-либо использовал Post(), если вся идея использования блоков данных заключается в создании параллельной и асинхронной среды.
Конечно, технически я понимаю разницу в том, что Post() возвращает bool, тогда как SendAsync возвращает ожидаемую задачу bool. Но какое это имеет значение? Когда будет когда-либо задерживаться возврат bool (который, как я понимаю, является подтверждением того, был ли элемент помещен в очередь блока данных)? Я понимаю общую идею структуры параллелизма async / await, но здесь это не имеет особого смысла, потому что кроме bool результаты того, что делается с переданным элементом, никогда не возвращаются вызывающей стороне, а вместо этого помещаются в "out-queue" и либо перенаправляется в связанные блоки данных, либо отбрасывается.
И есть ли разница в производительности между двумя методами при отправке товаров?
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);
}
Документация делает это достаточно ясно, ИМО. В частности, для Post
:
Этот метод вернется, как только целевой блок решит принять или отклонить элемент, но, если иное не определено специальной семантикой целевого блока, он не ожидает фактической обработки элемента.
А также:
Для целевых блоков, которые поддерживают откладывание предлагаемых сообщений, или для блоков, которые могут выполнять больше обработки в своих
Post
реализация, рассмотреть возможность использованияSendAsync
, который немедленно вернется и позволит цели отложить отправленное сообщение и позже использовать его послеSendAsync
возвращается.
Другими словами, в то время как оба являются асинхронными в отношении обработки сообщения, SendAsync
позволяет целевому блоку решать, принимать или нет сообщение асинхронно.
Это звучит как SendAsync
это, как правило, "более асинхронный" подход, который, вероятно, рекомендуется в целом. Что мне непонятно, так это то, почему оба требуются Post
в целом эквивалентно использованию SendAsync
а потом просто жду результата.