PFX ConcurrentQueue - ist es eine Möglichkeit, ein bestimmtes Element aus der Warteschlange zu entfernen

StackOverflow https://stackoverflow.com/questions/683956

  •  22-08-2019
  •  | 
  •  

Frage

Ich habe eine App, die eine ConcurrentQueue von Elementen hat, die eine ID-Eigenschaft und eine ConcurrentQueue von Aufgaben für jede Position hat, sehen die Warteschlange-Elemente wie:

class QueueItem {
  public int ID { get; set; }
  public ConcurrentQueue<WorkItem> workItemQueue { get; set; }
}

und die Warteschlange selbst wie folgt aussieht:

ConcurrentQueue<QueueItem> itemQueue;

Ich habe einen Thread eine foreach über die itemQueue tun, Warteschlangenauflösungs ein Element aus jeder Warteschlange und tut Arbeit auf sie:

foreach(var queueItem in itemQueue) {
  WorkItem workItem;
  if (queueItem.workItemQueue.TryDequeue(out workItem))
    doWork(workItem);
  else
    // no more workItems for this queueItem
}

Ich verwende ConcurrentQueues, weil ich einen eigenen Thread möglicherweise das Hinzufügen queueItems zum itemQueue haben, und das Hinzufügen von Workitems zu jedem workItemQueue.

Mein Problem kommt, wenn ich nicht mehr Workitems in einem queueItem haben - ich möchte, dass queueItem vom itemQueue entfernen - so etwas wie ...

  if (queueItem.workItemQueue.TryDequeue(out workItem))
    doWork(workItem);
  else
    itemQueue.TryRemove(queueItem);

... aber ich kann nicht einen Weg finden, das leicht zu tun. Die Art, wie ich habe kommen mit ist jede QueueItem aus der Warteschlange entfernt und dann Enqueue es, wenn es noch ist Workitems in der workItemQueue:

for (int i = 0; i < itemQueue.Count; i++) {
  QueueItem item;
  itemQueue.TryDequeue(out queueItem);
  if (queueItem.workItemQueue.TryDequeue(out workItem)) {
    itemQueue.Enqueue(queueItem);
    doWork(workItem);
  }
  else
    break;
}

Gibt es eine bessere Art und Weise zu erreichen, was ich will die PFX ConcurrentQueue, oder ist dies eine vernünftige Art und Weise, dies zu tun, sollte ich eine benutzerdefinierte gleichzeitige queue / Liste Implementierung verwenden oder ich etwas fehlt?

War es hilfreich?

Lösung

In der Regel gibt es keine effizienten Möglichkeiten, bestimmte Elemente aus Warteschlangen zu entfernen. Sie haben im Allgemeinen O (1) Warteschlange und entnimmt, sondern O (n) entfernt, das ist es, was die Implementierung der Fall ist.

Eine alternative Struktur ist etwas ein LinkedHashMap genannt. Werfen Sie einen Blick auf die Java-Implementierung wenn du interessierst dich.

Es ist im Wesentlichen eine Hashtabelle und eine verkettete Liste, die O (1) Warteschlange, dequeue ermöglicht und entfernen.

Dies ist in .NET noch nicht implementiert, aber es gibt ein paar Implementierungen rund um die Web schweben.

Nun, die Frage ist, warum ist itemQueue eine Schlange? Von Ihren Code-Beispielen, Sie einreihen oder nie etwas von ihm aus der Warteschlange entfernt (außer um das Entfernen Problem zu navigieren). Ich habe den Verdacht, dass Ihr Problem, wenn eine geeignete Datenstruktur vereinfacht werden könnte verwendet wird. Könnten Sie Beispiele, welche anderen Teile des Codes Zugriff geben itemQueue?

Andere Tipps

Dies kann nicht für alle, aber die folgende ist die Lösung kam ich mit für ein Element aus einer gleichzeitigen Warteschlange zu entfernen, da dies das erste Google-Ergebnis ist, dachte ich, ich würde meine Lösung hinter sich lassen.

Was ich tat, war vorübergehend die Arbeitswarteschlange mit einem leeren ersetzen, wandelt das Original auf eine Liste und entfernen Sie die Position (en), dann eine neue Warteschlange aus der modifizierten Liste erstellen und ihn wieder.

Code (sorry diese VB.net ist eher C #):

Dim found As Boolean = False
//'Steal the queue for a second, wrap the rest in a try-finally block to make sure we give it back
Dim theCommandQueue = Interlocked.Exchange(_commandQueue, New ConcurrentQueue(Of Command))
Try
    Dim cmdList = theCommandQueue.ToList()
    For Each item In cmdList
        If item Is whateverYouAreLookingFor Then
            cmdList.Remove(item)
            found = True
        End If
    Next
    //'If we found the item(s) we were looking for, create a new queue from the modified list.
    If found Then
        theCommandQueue = New ConcurrentQueue(Of Command)(cmdList)
    End If
Finally
    //'always put the queue back where we found it
    Interlocked.Exchange(_commandQueue, theCommandQueue)
End Try

Neben: Dies ist meine erste Antwort, so fühlen sich frei, einige Bearbeitung Beratung zu setzen und / oder meine Antwort bearbeiten

.

Warteschlangen gemeint sind, wenn Sie Elemente zu handhaben in einem FIFO-Stil, Stacks für LIFO wollen. Es gibt auch eine ConcurrentDictionary und ein concurrentbag. Stellen Sie sicher, dass eine Warteschlange tatsächlich ist das, was Sie wollen. Ich glaube nicht, dass ich jemals auf einem ConcurrentQueue ein foreach tun.

Was Sie wahrscheinlich wollen eine einzelne Warteschlange für Ihre Workitems ist (haben sie eine gemeinsame Schnittstelle verwenden und eine Warteschlange an der Schnittstelle zu machen, sollte die Schnittstelle die geerbte Art, auf die aussetzen später neu gefasst werden kann, wenn erforderlich). Wenn die Workitems zu einem Elternteil gehören, dann kann eine Eigenschaft verwendet werden, die einen Schlüssel für die Eltern halten wird (eine GUID für den Schlüssel betrachten), und die Eltern können je nach Bedarf in einer ConcurrentDictionary und referenziert / entfernt gehalten werden.

Wenn Sie es die Art und Weise tun, müssen Sie es haben, sollten Sie ein Flag hinzuzufügen. Sie können dann markieren Sie das Element in der itemqueue als ‚geschlossen‘ oder was auch immer, so dass, wenn es aus der Warteschlange entfernt wird, wird es ignoriert erhalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top