TPL Dataflow, qual è la differenza funzionale tra Post () e SendAsync ()?

Sono confuso circa la differenza tra l’invio di articoli tramite Post () o SendAsync (). La mia comprensione è che in tutti i casi una volta che un object ha raggiunto il buffer di input di un blocco di dati, il controllo viene restituito al contesto di chiamata, corretto? Allora perché dovrei mai aver bisogno di SendAsync? Se la mia ipotesi non è corretta, mi chiedo, al contrario, perché mai qualcuno utilizzerebbe Post () se l’idea di utilizzare i blocchi di dati è quella di stabilire un ambiente concorrente e asincrono.

Capisco ovviamente la differenza tecnicamente in quel Post () restituisce un valore booleano mentre SendAsync restituisce un’attività attendibile di bool. Ma quali implicazioni ha? Quando il ritorno di un bool (che capisco è una conferma se l’object è stato inserito nella coda del blocco dati o meno) viene mai ritardato? Comprendo l’idea generale del framework di concomitanza asincrona / attendi, ma qui non ha molto senso perché, a parte un bool, i risultati di tutto ciò che viene fatto all’elemento passato non vengono mai restituiti al chiamante ma inseriti in un “out-queue” e inoltrati a blocchi di dati collegati o scartati.

E c’è qualche differenza di prestazioni tra i due metodi quando si inviano gli oggetti?

Per vedere la differenza, hai bisogno di una situazione in cui i blocchi pospongono i loro messaggi. In questo caso, Post restituirà false immediatamente, mentre SendAsync restituirà un’attività che verrà completata quando il blocco decide cosa fare con il messaggio. L’ Task avrà un risultato true se il messaggio è accettato e un risultato false se non lo è.

Un esempio di situazione posticipata è un join non avido. Un esempio più semplice è quando si imposta BoundedCapacity :

 [TestMethod] public void Post_WhenNotFull_ReturnsTrue() { var block = new BufferBlock(new DataflowBlockOptions {BoundedCapacity = 1}); var result = block.Post(13); Assert.IsTrue(result); } [TestMethod] public void Post_WhenFull_ReturnsFalse() { var block = new BufferBlock(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(new DataflowBlockOptions { BoundedCapacity = 1 }); var result = block.SendAsync(13); Assert.IsTrue(result.IsCompleted); } [TestMethod] public void SendAsync_WhenFull_ReturnsIncompleteTask() { var block = new BufferBlock(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(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(new DataflowBlockOptions { BoundedCapacity = 1 }); block.Post(13); var task = block.SendAsync(13); block.Complete(); var result = await task; Assert.IsFalse(result); } 

La documentazione lo rende ragionevolmente chiaro, IMO. In particolare, per Post :

Questo metodo tornerà quando il blocco target ha deciso di accettare o rifiutare l’object, ma se non diversamente dettato dalla semantica speciale del blocco di destinazione, non attende che l’object venga effettivamente elaborato.

E:

Per i blocchi di destinazione che supportano il posticipo dei messaggi offerti, o per i blocchi che potrebbero eseguire più elaborazioni nella loro implementazione Post , considerare l’utilizzo di SendAsync , che verrà restituito immediatamente e consentirà alla destinazione di posticipare il messaggio pubblicato e successivamente di consumarlo dopo il ritorno di SendAsync .

In altre parole, mentre entrambi sono asincroni rispetto all’elaborazione del messaggio, SendAsync consente al blocco di destinazione di decidere se accettare o meno il messaggio in modo asincrono.

Sembra che SendAsync sia un approccio generalmente “più asincrono”, e che è probabilmente incoraggiato in generale. Ciò che non mi è chiaro è il motivo per cui entrambi sono richiesti, poiché sembra che Post sia sostanzialmente equivalente all’utilizzo di SendAsync e quindi attende solo il risultato.