2014-04-06 16 views
5

Voglio impostare un TransformBlock che elabora il suo articolo in parallelo. Così, sto impostando ExecutionDataflowBlockOptions.MaxDegreeOfParallelism a> 1. Non mi interessa circa l'ordine dei messaggi, ma la documentation dice:Come è possibile specificare un blocco di esecuzione non ordinato utilizzando la libreria TPL Dataflow?

Quando si specifica il massimo grado di parallelismo che è maggiore di 1, più messaggi sono elaborati contemporaneamente e, pertanto, i messaggi potrebbero non essere elaborati nell'ordine in cui sono stati ricevuti. Tuttavia, l'ordine con cui i messaggi vengono emessi dal blocco verrà ordinato correttamente.

"ordinato correttamente" significa che se c'è un messaggio nella coda che richiede un lungo tempo di elaborazione, non vengono emessi ulteriori messaggi fino a quando questo messaggio non viene elaborato?

E se sì, come posso specificare un blocco di esecuzione (ad esempio un TransformBlock) a cui non interessa l'ordine? O devo specificare al consumo che non mi interessa ordinare?

risposta

5

Non esiste un blocco di questo tipo nella libreria, ma è possibile crearlo facilmente combinando uno ActionBlock e uno BufferBlock. Qualcosa di simile:

public static IPropagatorBlock<TInput, TOutput> 
    CreateUnorderedTransformBlock<TInput, TOutput>(
    Func<TInput, TOutput> func, ExecutionDataflowBlockOptions options) 
{ 
    var buffer = new BufferBlock<TOutput>(options); 
    var action = new ActionBlock<TInput>(
     async input => 
     { 
      var output = func(input); 
      await buffer.SendAsync(output); 
     }, options); 

    action.Completion.ContinueWith(
     t => 
     { 
      IDataflowBlock castedBuffer = buffer; 

      if (t.IsFaulted) 
      { 
       castedBuffer.Fault(t.Exception); 
      } 
      else if (t.IsCanceled) 
      { 
       // do nothing: both blocks share options, 
       // which means they also share CancellationToken 
      } 
      else 
      { 
       castedBuffer.Complete(); 
      } 
     }); 

    return DataflowBlock.Encapsulate(action, buffer); 
} 

In questo modo, una volta che un elemento viene elaborato dal ActionBlock, è immediatamente spostato nella BufferBlock, che significa ordinamento non viene mantenuta.

Un problema con questo codice è che esso non osserva l'insieme BoundedCapacity bene: in effetti, la capacità di questo blocco è il doppio della capacità impostato nelle opzioni (poiché ciascuno dei due blocchi ha una capacità separato).

+0

Grazie! Questo dovrebbe essere usato come esempio su https://msdn.microsoft.com/en-us/library/hh228606(v=vs.110).aspx, in quanto chiarisce che Encapsulate è utile per cambiare il modo in cui un flusso di dati lavori. – nlawalker

+1

GuaranteOrdered è stato aggiunto a DataflowBlockOptions nel 2016 con TransformBlock e TransformManyBlock che lo implementano. Per un set TransformBlock non ordinato, Conferma ordine su falso in DataflowBlockOptions https://github.com/dotnet/corefx/pull/5191 – NPNelson