32

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 oggetto 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.TPL Dataflow, qual è la differenza funzionale tra Post() e SendAsync()?

Comprendo 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'oggetto è 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 articoli?

risposta

39

Per vedere la differenza, è necessaria una situazione in cui i blocchi posticipano i loro messaggi. In questo caso, Post restituirà immediatamente false, mentre SendAsync restituirà un Task che verrà completato quando il blocco decide cosa fare con il messaggio. Il Task avrà un risultato true se il messaggio è accettato e un risultato false in caso contrario.

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<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); 
} 
+0

ok ma data la tua spiegazione, allora qual è la logica dietro 'Task '? Se non può essere inviato immediatamente a causa del posticipo, ma l'attività termina in un secondo momento, qual è la differenza tra il vero bool e il falso? –

+1

Il blocco può eventualmente decidere di rifiutare quel messaggio (ad es., Se si completa il blocco), nel qual caso il risultato dell'attività sarà 'falso'. Vedi risposta aggiornata. –

+0

grandioso, questo ora ha perfettamente senso, questa possibilità mi è completamente sfuggita di mente. Molte grazie. –

7

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

Questo metodo restituirà una volta che il blocco di destinazione ha deciso di accettare o rifiutare la voce, ma se non diversamente dettato dalla semantica speciali del blocco di destinazione, non aspettare che l'elemento di realtà essere elaborato

E:

Per i blocchi di destinazione che supportano rinviare i messaggi offerti, o per i blocchi che possono fare di più di elaborazione nella loro Post realizzazione, considerare l'utilizzo di SendAsync, che restituirà immediatamente e consentirà l'obiettivo di rimandare il messaggio postato e consumarlo successivamente dopo i ritorni SendAsync.

In altre parole, mentre entrambi sono asincrone rispetto al elaborazione il messaggio, SendAsync permette il blocco di destinazione per decidere o meno di accettare il messaggio in modo asincrono troppo.

Sembra che SendAsync sia un approccio generalmente "più asincrono", e che è probabilmente incoraggiato in generale. Che cosa è non è chiaro per me è perché entrambi sono necessari, in quanto suona certamente comeè sostanzialmente equivalente all'utilizzo di SendAsync e quindi solo in attesa del risultato.

+0

grazie, lo ha reso un po 'più chiaro se la tua ultima frase riassume la mia confusione rimanente. Dai miei test, quando un blocco dati rifiuta di accettare un messaggio non ho visto alcun vantaggio nell'usare SendAsync su Post, entrambi non hanno tentato di ri-consegnare il messaggio quando il blocco di dati segnala che accetta i messaggi in un momento successivo. (entrambi restituiscono immediatamente se il messaggio viene rifiutato ed entrambi restituiscono immediatamente se il messaggio è accettato). In questo la semantica di "accettare" il messaggio re Post vs SendAsync è ancora nebulosa per me. –

+0

Immagino di non capire quanta latenza possa potenzialmente essere introdotta nel meccanismo di "accettazione/declino" dei nuovi messaggi passati. Finora non ho mai visto ritardi misurabili tra il passaggio e l'arrivo di un messaggio nella coda di input/rifiuto dalla coda. Ma grazie comunque per mettere l'accento sulla parte "accettazione/rifiuto" del problema. –

+3

@Freddy: Certo, ma la differenza è quando un blocco * posticipa * la decisione di accettazione/rifiuto. Forse il blocco target che stai usando non lo fa mai, naturalmente. –

Problemi correlati