- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
有时,当我调用 ConcurrentDictionary.ToArray 时,会出现以下错误。错误如下:
System.ArgumentException: The index is equal to or greater than the length of the array, or the number of elements in the dictionary is greater than the available space from index to the end of the destination array. at System.Collections.Concurrent.ConcurrentDictionary
2.System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>.CopyTo(KeyValuePair
2[] array, Int32 index) at System.Linq.Buffer1..ctor(IEnumerable
1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)
2.RemoveExcessAsync(Object state) in ...\SlidingCache.cs:line 141 at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch()
at ...Cache.SlidingCache
我注意到在多线程场景中,有时在对 ConcurrentDictionary 进行排序时会出现异常。参见堆栈溢出问题 here .所以我在排序之前开始使用 ConcurrentDictionary.ToArray。创建数组时似乎仍然存在问题。
并发字典用于维护对象的缓存,并在达到为缓存设置的最大元素数时刷新最后访问的对象。缓存由多个线程访问,并且在尝试删除旧元素以便可以将新元素添加到数组时发生上述错误。请查看下面的一些代码片段:
public class SlidingCache<TKey, TValue> : IDictionary<TKey, TValue>
{
public int MinCount { get; private set; }
public int MaxCount { get; private set; }
private readonly IDictionary<TKey, CacheValue> _cache = new ConcurrentDictionary<TKey, CacheValue>();
public SlidingCache(int minCount=75000, int maxCount=100000)
{
if (minCount <= 2)
throw new ArgumentException("minCount");
if (maxCount <= minCount)
throw new ArgumentException("maxCount");
MinCount = minCount;
MaxCount = maxCount;
}
#region IDictionary<TKey, TValue>
public int Count
{
get { return _cache.Count; }
}
public TValue this[TKey key]
{
get
{
return _cache[key].Value;
}
set
{
_cache[key]=new CacheValue(value);
RemoveExcess();
}
}
...
#endregion
private void RemoveExcess()
{
if (this.Count <= this.MaxCount || Interlocked.Increment(ref _removingExcess) != 1)
return;
ThreadPool.QueueUserWorkItem(RemoveExcessAsync, null);
}
private int _removingExcess;
private void RemoveExcessAsync(object state)
{
var remove = _cache.ToArray().OrderByDescending(i => i.Value.LastRequestTime).Take(MaxCount - MinCount);
foreach (var pair in remove)
{
_cache.Remove(pair.Key);
}
Interlocked.Exchange(ref _removingExcess, 0);
}
任何人都可以解释上述异常的潜在原因和任何解决方法吗?
谢谢。
最佳答案
那是因为 Enumerable.ToArray
不能安全地用于并发集合。
您应该将内部变量声明为ConcurrentDictionary
类型而不是IDictionary
,因为这将使用字典实现的ToArray
实现本身,而不是依赖于扩展方法:
private readonly IDictionary<TKey, CacheValue> _cache = new ConcurrentDictionary<TKey, CacheValue>();
特别是,Enumerable.ToArray
最终在内部使用了一个 Buffer
类,下面是该类的构造函数是如何定义的(它的开头):
(来自 Enumerable.cs - reference source)
internal Buffer(IEnumerable<TElement> source) {
TElement[] items = null;
int count = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
如您所见,它使用字典的 Count
属性,创建一个数组,然后将元素复制到数组中。如果基础字典在读取 Count
之后但在 CopyTo
之前至少获得了一项,那么您就会遇到问题。
您可以将其与使用锁定的字典本身内的 ToArray
实现进行对比:
(来自 ConcurrentDictionary.cs - reference source)
public KeyValuePair<TKey, TValue>[] ToArray()
{
int locksAcquired = 0;
try
{
AcquireAllLocks(ref locksAcquired);
int count = 0;
checked
{
for (int i = 0; i < m_tables.m_locks.Length; i++)
{
count += m_tables.m_countPerLock[i];
}
}
KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[count];
CopyToPairs(array, 0);
return array;
}
finally
{
ReleaseLocks(0, locksAcquired);
}
}
关于c# - .NET ConcurrentDictionary.ToArray() 参数异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29648849/
我在我的网络应用程序中创建了一个 ConcurrrentDictionary 作为应用程序对象。它在 session 之间共享。 (基本上用作存储库。) 有时,任何可用的 session 都会将新项目
ConcurrentDictionary.TryUpdate 方法需要与具有指定键的元素的值进行比较的 comparisonValue。但是如果我想做这样的事情: if (!_store.TryGet
如果我有一个 ConcurrentDictionary例如,我是否使用 Count 有关系吗?属性(property)或LINQ的Any() ?我宁愿写 dict.Any()而不是 dict.Coun
我正在使用并发字典来存储大约200万条记录,并且想知道如何初始化字典的并发级别。 MSDN页面的示例代码中具有以下注释: concurrencyLevel越高,可以在ConcurrentDiction
我正在使用 ConcurrentDictionary 来存储日志行,当我需要向用户显示它们时,我调用 ToList()生成一个列表。但奇怪的是,一些用户在列表中最先收到最近的行,而从逻辑上讲,他们应该
我发现这个 C# 扩展将 GetOrAdd 转换为 Lazy,我想对 AddOrUpdate 做同样的事情。 有人可以帮我将其转换为 AddOrUpdate 吗? public static cla
我对并发字典如何锁定他们的资源感到困惑。 例如,如果我运行一个方法来迭代字典中的每个项目并在一个线程中编辑它的值,然后我尝试从另一个线程读取一个键的值: 第二个线程会访问字典的快照吗? 如果没有,如果
我找不到有关 ConcurrentDictionary 类型的足够信息,因此我想在这里询问一下。 目前,我使用字典来保存由多个线程(来自线程池,因此没有确切数量的线程)不断访问的所有用户,并且它具有同
我在 Azure 应用服务上使用 MVC 5、ASP.NET 4.7 我正在使用 ConcurrentDictionary 对象来保存数据,以保存对数据源的多次调用。 关于其行为的几个问题: 1) 填
我想使用 ConcurrentDictionary 来检查之前是否添加了这个数据键,但看起来我仍然可以添加之前添加的键。 代码: public class pKeys {
我正在按照教程构建聊天客户端和服务器,现在我遇到了以下错误: Inconsistent accessibility: field type 'System.Collections.Concurrent
我正在考虑将类(单例)与使用 ConcurrentDictionary 实现的集合一起使用。此类将用作缓存实现 (asp.net/wcf)。 您如何看待从此类中显式公开这些集合与仅公开例如3 种方法(
有一个并发字典,它从不同的来源收集信息,每分钟刷新一次并将收集的数据传递给另一个处理程序。 var currentDictionarySnapshot = _currentDictionary; _c
我在 static 类中有一个静态 ConcurrentDictionary。在该类的静态构造函数中,我通过 Task.Run 调用一个私有(private)方法来无限循环遍历字典并删除已过期的项目,
我在 StackOverflow 上阅读了以下文章:ConcurrentBag - Add Multiple Items?和 Concurrent Dictionary Correct Usage但答
我存储这个类 public class Customer { public string Firstname { get; set; } public string Lastname
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关于您编写的代码问题的问题必须在问题本身中描述具体问题 — 并且包括有效代码 以重现它。参见 SSC
我正在编写一些使用反射的代码。所以我试图将昂贵的反射处理缓存到 ConcurrentDictionary 中。但是,我想对并发字典应用限制,以防止存储旧的和未使用的缓存值。 我做了一些研究以了解如何限
好吧,所以我遇到了一个奇怪的小问题,坦率地说,我没有想法。我想把它扔出去看看我是否遗漏了我做错的东西,或者 ConcurrentDictionary 是否工作不正常。这是代码: (缓存是一个包含静态
我正在尝试使用 ConcurrentDictionary 来帮助完成过滤任务。 如果一个数字出现在列表中,那么我想将一个条目从一个字典复制到另一个。 但这部分的 AddOrUpdate 是不对的 -
我是一名优秀的程序员,十分优秀!