2011-01-13 21 views
10

Estoy creando un servicio de Windows que hace uso de un FileSystemWatcher para controlar una carpeta en particular para adiciones de un tipo de archivo en particular. Debido a la brecha entre el evento Creado y cuando el archivo está realmente listo para ser manipulado, creé un Queue<T> para contener los nombres de los archivos que necesitan procesarse. En el controlador de eventos Creado, el elemento se agrega a la cola. Luego, usando un temporizador, periódicamente tomo el primer elemento de la cola y lo proceso. Si el proceso falla, el elemento se agrega a la cola para que el servicio pueda intentar procesarlo más tarde.¿Cómo agrego un artículo al principio de la cola?

Esto funciona bien, pero he encontrado que tiene un efecto secundario: el primer intento de procesamiento de nuevos elementos no ocurre hasta que se vuelven a intentar todos los elementos de nuevo intento. Como es posible que la cola contenga muchos elementos, me gustaría forzar los nuevos elementos al principio de la cola para que se procesen primero. Pero desde el Queue<T> documentation, no hay una forma obvia de agregar un elemento al frente de la cola.

Supongo que podría crear una segunda cola para nuevos elementos y procesarla de forma preferencial, pero tener una sola cola parece más simple.

¿Hay alguna manera fácil de agregar un elemento al principio de la cola?

+5

Si está añadiendo al frente y cola de una cola, deja de ser una cola, hablando pedante. – CanSpice

+0

¿por qué no agregar los elementos de reintentos a su propia colección para procesarlos más tarde? –

+0

En el STL usaría un deque (que he oído pronunciado como "mazo" pero realmente no lo sé). Es una cola doble. http://www.cplusplus.com/reference/stl/deque/ No parece que haya uno en System.Collections.Generic, pero puede escribirlo de la forma que describe. –

Respuesta

25

En cierto modo se parece a un LinkedList<T> desea, lo que le permite hacer cosas como AddFirst(), AddLast(), RemoveFirst(), y RemoveLast().

+0

+1 Eso es realmente una gran solución. Doh, ¿por qué no pensé eso? –

+0

+++ Una gran solución de hecho. Esto es lo que estaba buscando; una cola que no es realmente una cola. :) – Corin

+2

Como una ventaja adicional, LinkedList está doblemente vinculado, por lo que todas las operaciones enumeradas anteriormente son O (1). – pR0Ps

3

Bueno, estoy de acuerdo con CanSpice; Sin embargo, usted podría:

var items = queue.ToArray(); 
queue.Clear(); 
queue.Enqueue(newFirstItem); 
foreach(var item in items) 
    queue.Enqueue(item); 

truco desagradable, pero va a trabajar;)

Más bien se podría pensar en añadir una segunda instancia de cola. Esta es la cola de 'prioridad' que usted revisa/ejecuta primero. Esto sería un poco más limpio. Incluso puede crear su propia clase de cola para envolverlo todo bien y pulcro;)

+0

Se me ocurrió vaciar la cola y volver a llenarla, pero imaginé un mecanismo mucho más feo de lo que usted propone. Sin embargo, una clase de cola personalizada es intrigante. – Corin

2

Parece que lo que está buscando es un Stack - Este es un buffer LIFO (último en entrar, primero en salir).

+1

-1, solo quiere que se inserten ciertos tipos de elementos al principio de la cola, no todos. Por lo tanto, un Stack es tan defectuoso para su propósito. –

+0

@ csharptest.net, he leído tres veces la pregunta del OP, y no es así como me escanea. Me parece que OP * always * quiere que se procesen nuevos elementos antes que los viejos. –

+0

@Kirk Originalmente pensé eso también, pero después de volver a leerlo parece que quiere que todos los artículos nuevos tengan prioridad sobre los viejos (independientemente de cuánto tiempo hayan estado esperando los viejos) – Rob

7

Simplemente use el método Peek en la devolución de llamada del temporizador en lugar de Dequeue. Si el proceso tiene éxito, luego dequeue el elemento.

1

Sugiero usar dos colas: una para los elementos nuevos y otra para los elementos de nuevo. Envuelva ambas colas en un solo objeto que tenga la misma semántica que una cola en lo que respecta a la eliminación, pero le permite marcar las cosas como yendo a la cola Nueva o a la cola de Reintentar en la inserción. Algo así como:

public class DoubleQueue<T> 
{ 
    private Queue<T> NewItems = new Queue<T>(); 
    private Queue<T> RetryItems = new Queue<T>(); 

    public Enqueue(T item, bool isNew) 
    { 
     if (isNew) 
      NewItems.Enqueue(item); 
     else 
      RetryItems.Enqueue(item); 
    } 

    public T Dequeue() 
    { 
     if (NewItems.Count > 0) 
      return NewItems.Dequeue(); 
     else 
      return RetryItems.Dequeue(); 
    } 
} 

Por supuesto, usted necesita tener una propiedad Count que devuelve el número de elementos en ambas colas.

Si tiene más de dos tipos de artículos, entonces es hora de actualizar a una cola de prioridad.

+0

No tiene sentido. Queue es cola. Él debería usar la lista enlazada. – zgnilec

+1

El problema con el enfoque de la lista enlazada es que realmente no debería poner todos los elementos nuevos en el frente, a pesar de lo que está pidiendo literalmente. Quiere que se procesen los artículos nuevos antes de que se vuelvan a intentar los artículos. No quiere que se procesen nuevos elementos antes de los nuevos artículos más antiguos. Por lo tanto, la solución adecuada son dos colas, y esto lo envuelve decentemente. –

Cuestiones relacionadas