Me preguntaba si hay beneficios asociados con el uso de un BufferBlock vinculado a uno o muchos ActionBlocks, aparte de la regulación (usando BoundedCapacity), en lugar de solo publicar directamente en ActionBlock (s) (como siempre que no se requiera estrangulamiento).Beneficios de usar BufferBlock <T> en redes de flujo de datos
Respuesta
Si todo lo que desea hacer es reenviar elementos de un bloque a varios otros, no necesita BufferBlock
.
Pero ciertamente hay casos en que es útil. Por ejemplo, si tiene una red de flujo de datos compleja, es posible que desee construirla a partir de subredes más pequeñas, cada una creada en su propio método. Y para hacer esto, necesitas alguna forma de representar un grupo de bloques. En el caso que usted mencionó, devolver ese único BufferBlock
(probablemente como ITargetBlock
) del método sería una solución fácil.
Otro ejemplo en el que BufferBlock
sería útil es si desea enviar elementos de varios bloques de origen a varios bloques de destino. Si utilizó BufferBlock
como intermediario, no tiene que conectar cada bloque de origen a cada bloque de destino.
Estoy seguro de que hay muchos otros ejemplos donde puede usar BufferBlock
. Por supuesto, si no ve ningún motivo para usarlo en su caso, no lo haga.
Para agregar a la respuesta de svick, hay otra ventaja de los bloques de almacenamiento. Si tiene un bloque con múltiples enlaces de salida y desea equilibrarlos, debe convertir los bloques de salida en no codiciosos y agregar un bloque de almacenamiento para manejar la cola. He encontrado el siguiente ejemplo útil:
Citado de un enlace que está ahora muerto:
Esto es lo que estamos planeando hacer:
- Algunos bloque de código va a publicar datos a la BufferBlock utilizando su Método de publicación (T t).
- Este BufferBlock está vinculado a 3 instancias ActionBlock utilizando el método LinkTo t) de BufferBlock.
Nota, que no BufferBlock copias de transferencia de los datos de entrada a todos los bloques de destino se vincula to.Instead lo hace a un bloque de destino only.Here estamos esperando que cuando un objetivo está ocupado procesando la solicitud. Será entregado al otro objetivo.Ahora vamos a hacer referencia al código de abajo:
static void Main(string[] args)
{
BufferBlock<int> bb = new BufferBlock<int>();
ActionBlock<int> a1 = new ActionBlock<int>((a) =>
{
Thread.Sleep(100);
Console.WriteLine("Action A1 executing with value {0}", a);
}
);
ActionBlock<int> a2 = new ActionBlock<int>((a) =>
{
Thread.Sleep(50);
Console.WriteLine("Action A2 executing with value {0}", a);
}
);
ActionBlock<int> a3 = new ActionBlock<int>((a) =>
{
Thread.Sleep(50);
Console.WriteLine("Action A3 executing with value {0}", a);
}
);
bb.LinkTo(a1);
bb.LinkTo(a2);
bb.LinkTo(a3);
Task t = new Task(() =>
{
int i = 0;
while (i < 10)
{
Thread.Sleep(50);
i++;
bb.Post(i);
}
}
);
t.Start();
Console.Read();
}
Cuando ejecuta produce el siguiente resultado:
- Acción A1 ejecutar con valor 1
- Acción A1 ejecutar con un valor de 2
- Acción A1 ejecución con valor 3
- Acción A1 ejecutar con valor 4
- Acción A1 ejecutar con valor 5
- Acción A1 ejecución con valor 6
- Acción A1 ejecución con valor 7
- Acción A1 ejecución con valor 8
- Acción A1 ejecución con valor 9
- Acción A1 ejecución con valor 10
Esto muestra que solo un objetivo está ejecutando todos los datos, incluso cuando está ocupado (debido a Thread.Sleep (100) agregado deliberadamente). ¿Por qué?
Esto se debe a que todos los bloques de destino son de naturaleza por defecto codiciosa y almacena la entrada de entrada incluso cuando no pueden procesar los datos. Para cambiar este comportamiento, hemos establecido la propiedad Greedy en falso en DataFlowBlockOptions mientras se inicializa ActionBlock como se muestra a continuación.
static void Main(string[] args)
{
BufferBlock<int> bb = new BufferBlock<int>();
ActionBlock<int> a1 = new ActionBlock<int>((a) =>
{
Thread.Sleep(100);
Console.WriteLine("Action A1 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: 1,
cancellationToken: CancellationToken.None,
//Not Greedy
greedy: false)
);
ActionBlock<int> a2 = new ActionBlock<int>((a) =>
{
Thread.Sleep(50);
Console.WriteLine("Action A2 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: -1,
cancellationToken: CancellationToken.None,
greedy: false)
);
ActionBlock<int> a3 = new ActionBlock<int>((a) =>
{
Thread.Sleep(50);
Console.WriteLine("Action A3 executing with value {0}", a);
}
, new DataflowBlockOptions(taskScheduler: TaskScheduler.Default,
maxDegreeOfParallelism: 1, maxMessagesPerTask: -1,
cancellationToken: CancellationToken.None,
greedy: false)
);
bb.LinkTo(a1);
bb.LinkTo(a2);
bb.LinkTo(a3);
Task t = new Task(() =>
{
int i = 0;
while (i < 10)
{
Thread.Sleep(50);
i++;
bb.Post(i);
}
}
);
t.Start();
Console.Read();
}
La salida de este programa es:
- Acción A1 ejecución con valor 1
- Acción A2 ejecución con valor 3
- Acción A1 ejecución con valor 2
- Acción A3 ejecución con valor 6
- Acción A3 que se ejecuta con el valor 7
- Acción A3 ejecución con valor 8
- Acción A2 ejecución con valor 5
- Acción A3 ejecución con valor 9
- Acción A1 ejecución con valor 4
- Acción A2 ejecución con valor 10
Este claramente una distribución de los datos en tres ActionBlock (s) como se esperaba.
No se pudo obtener el segundo ejemplo para compilar. – Nathan
No, el segundo ejemplo no se compilará por una serie de razones: solo es posible establecer greedy = false para un bloque de flujo de datos "de agrupación", no para un bloque de ejecución; y luego tiene que establecerse a través de GroupingDataflowBlockOptions - no DataflowBlockOptions; y luego se establece como un valor de propiedad "{Greedy = false}" no como un parámetro de constructor.
Si desea reducir la capacidad de un bloque de acción, hágalo estableciendo el valor de la propiedad BoundedCapacity de DataflowBlockOptions (aunque, como indica el OP, ya conocen esta opción).De esta manera:
var a1 = new ActionBlock<int>(
i => doSomeWork(i),
new ExecutionDataflowBlockOptions {BoundedCapacity = 1}
);
- 1. ¿Beneficios de usar Spring EL sobre OGNL?
- 2. ¿Beneficios de usar un constructor?
- 3. beneficios de usar directoryperdb en MongoDB
- 4. Flujo de control de SSIS frente al flujo de datos
- 5. ¿Cuáles son los beneficios de usar un bindingsource con bindinglist <business obj> como fuente de datos?
- 6. Computación de flujo de datos en python
- 7. ¿Cuáles son los beneficios de usar WCF?
- 8. ¿Cuáles son los beneficios de usar Clases en VBA?
- 9. ¿Cuáles son los beneficios de usar view en la base de datos?
- 10. Insertar datos de usuario en flujo Mpeg
- 11. necesidad de datos de flujo de entrada
- 12. Objetivo-c: ¿beneficios de usar NSCache sobre un NSMutableDictionary estático?
- 13. Vinculación de ActionBlocks creados dinámicamente a un BufferBlock
- 14. ¿Cuáles son los beneficios de usar Scala en .Net?
- 15. ¿Cuáles son los mayores beneficios de usar INDEXES en mysql?
- 16. Módulos Perl fáciles de usar para redes neuronales
- 17. Detección de la configuración "Usar solo redes 2G"
- 18. Beneficios de eventos utilizando EventArgs/EventArgs <T> tipos de delegado en lugar de ...
- 19. Beneficios clave de MSMQ
- 20. Redes de nivel de paquetes en Android
- 21. los beneficios de awakeFromNib?
- 22. Mercurial y NTFS Flujo de datos alternativo
- 23. Optimización del flujo de datos usando HOOPL
- 24. Beneficios de matrices
- 25. Referencia de redes neuronales artificiales
- 26. Beneficios de object.get() vs object.read() en Grails
- 27. ¿Hay alguna manera de generar automáticamente diagramas de flujo de datos y diagramas de flujo?
- 28. ¿Cuáles son los beneficios de no usar cPickle para crear un almacenamiento persistente para los datos?
- 29. Proyecto de redes neuronales?
- 30. Cuándo usar Algoritmos genéticos vs. cuándo usar redes neuronales?
me siento que el uso de BufferBlocks es la forma más "limpia" de comunicación entre bloques de flujo de datos, sino que es la cabeza (si lo hay) de la utilización de BufferBlocks vale la pena? – Dimitri
Eso es para que usted decida. Si crees que hace que tu código sea más limpio, hazlo. Tiene algunos gastos generales, pero creo que no debería ser notable, a menos que realmente se preocupe por el rendimiento. – svick