.NET ConcurrentDictionary.ToArray () ArgumentException

8

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.Buffer 1..ctor(IEnumerable 1 Quelle)      bei System.Linq.Enumerable.ToArray [TSource] (IEnumerable 1 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.

    
Kess 15.04.2015, 11:20
quelle

1 Antwort

13

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:

%Vor%

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:

(aus ConcurrentDictionary.cs - Referenzquelle )

%Vor%     
Lasse Vågsæther Karlsen 15.04.2015, 11:26
quelle