Manchmal erhalte ich den Fehler, wenn ich ConcurrentDictionary.ToArray aufruft. Fehler unten:
System.ArgumentException: Der Index ist gleich oder größer als die Länge des Arrays oder die Anzahl der Elemente im Wörterbuch ist größer als der verfügbare Speicherplatz vom Index bis zum Ende des Zielarrays. bei System.Collections.Concurrent.ConcurrentDictionary
2.System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>.CopyTo(KeyValuePair
2 [] -Array, Int32-Index) bei System.Linq.Buffer1..ctor(IEnumerable
1 Quelle) bei System.Linq.Enumerable.ToArray [TSource] (IEnumerable1 source) at ...Cache.SlidingCache
2.RemoveExcessAsync (Objektstatus) in ... \ SlidingCache.cs: Zeile 141 bei System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback-Callback, Objektstatus, Boolean preserveSyncCtx) bei System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback-Callback, Objektstatus, Boolean preserveSyncCtx) bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () bei System.Threading.ThreadPoolWorkQueue.Dispatch ()
Ich habe festgestellt, dass Sie in Multithread-Szenarien manchmal Ausnahmen beim Sortieren des ConcurrentDictionary erhalten. Siehe Stapelüberlauffrage hier . Also habe ich ConcurrentDictionary.ToArray vor dem Sortieren verwendet. Es scheint, dass auch beim Erstellen des Arrays Probleme auftreten.
Das Concurrent Dictionary wird für einen Cache verwendet, der Objekte verwaltet und die zuletzt aufgerufenen Objekte löscht, wenn die maximale Anzahl von Elementen für den Cache erreicht ist. Auf den Cache wird von mehreren Threads zugegriffen, und der obige Fehler tritt auf, wenn versucht wird, ältere Elemente zu entfernen, so dass neue Elemente zum Array hinzugefügt werden können. Bitte beachten Sie einige Codefragmente unten:
%Vor%Kann jemand den möglichen Grund für die obige Ausnahme und etwaige Umgehungen erklären?
Danke.
Das liegt daran, dass Enumerable.ToArray
nicht für gleichzeitige Sammlungen geeignet ist.
Sie sollten Ihre interne Variable vom Typ ConcurrentDictionary
und nicht IDictionary
deklarieren, da dies die Implementierung ToArray
des Wörterbuchs selbst verwenden würde, anstatt sich auf die Erweiterungsmethode zu verlassen:
Insbesondere endet Enumerable.ToArray
intern mit einer Buffer
-Klasse, und hier ist der Konstruktor dieser Klasse definiert (der Anfang davon):
(aus Enumerable.cs - Referenzquelle )
%Vor% Wie Sie sehen, wird die Count
-Eigenschaft des Dictionary verwendet, ein Array erstellt und anschließend die Elemente in das Array kopiert. Wenn das zugrundeliegende Wörterbuch nach dem Lesen von Count
, aber vor CopyTo
mindestens ein anderes Element erhalten hat, erhalten Sie Ihr Problem.
Sie können das mit der Implementierung von ToArray
im Wörterbuch selbst vergleichen, das locking verwendet:
Tags und Links c# multithreading concurrentdictionary