关于集合

那些年你用的集合

.NET有超过20种内置的集合类型,.NET Framework中有些集合只是为了保持向后兼容性,新的代码种绝不应该再去使用以下集合

ArrayList

Hashtable

Queue

SortedList

Stack

ListDictionary

HybridDictionary

为啥呢?因为会发生类型转换和装箱操作。,上述集合类保存的都是对Object实例的引用,所以你总要转换未实际的对象类型,装箱是最严重的问题。

试着用这些集合

1:假设访问有一个Int32类型的ArrayList,每个成员都会单独装箱并保存在内存堆中,为了访问所有的Int32成员,并不是像对联系存放的内存数组那样遍历,而是需要对每个引用进行一次指针间接引用,再访问内存堆(丧失了就近访问可能性),在进行一次拆箱操作获取内部的数据值。所以下面可替换为

关于集合

Dictionary实现为一个哈希表,插入和读取 操作的时间复杂度为O(1)

SortedDictionary实现为二叉树,插入和读取操作的时间复杂度为O(log n)

SortedList实现为有序数组,读取操作的时间为O(log n),最坏为O(n),内存需求最少,

HashSet 使用了哈希表,插入和删除操作O(1)

SortedSet使用了二叉树,插入和删除操作O(log n)

List,StarcK,Queue在内部都使用了数组,操作数据量大的时候效率较高,事先如果知道成员的大小,应该把所需的内存预先分配好,这样是避免CPU和GC开销去调整数组的大小。

并发访问的集合类

 

1|0System.Collections.Concurrent命名空间

ConcurrentBag<T>

ConcurrentDictionary<TKey,TValue>

ConcurrentQueue<T>

ConcurrentStack<T>

......

大部分内容使用了Interlocked或Monitor作为同步原语

 以上需要注意

TryXXX方法,但当其他线程正在操作而发生冲突时,就会失败

如ConcurrentStarkTryPop当其他线程正在操作而发生冲突时,就会返回false,

ConcurrentDictionary可调用TryAdd,或者用TryUpdate。

AddOrUpdate不能直接给出新数据,而是需要传入两个委托,分别用于添加和修改操作.

第一个委托,键不存在,返回对应的值

第二个委托,键存在,返回新值或已存在的值

其实不管键存在不存在,都会返回新值,你需要明白一个新值可能并非来自当前线程发起的AddOrUpdate调用,这些方法是线性安全的,但不是原子性,可能其他线程用同一个键调用了方法,第一个线程返回了第二个线程返回的值。

 为啥不直接传入数据,而用委托,因为很多时候给的键生成值是一件开销很大的操作,你不希望两个线程同时进行这种操作,委托可以让你使用现有的数据,而不是在生成一份新的拷贝。委托不一定只会调用一次,如果要保证添加和修改的同步性,还需要在委托中添加同步代码。

1:SortedDictionary<TKey,TValue> 类

表示根据键进行排序的键/值对的集合。

比较:泛型类是具有 O (log n)检索的二进制搜索树,其中 n 是字典中的元素数。 在这方面,它类似SortedList<TKey,TValue>于泛型类。 这两个类具有相似的对象模型,两者都有 O (log n)检索。 这两个类的不同之处在于内存使用和插入和删除的速度:

使用TryGetValue方法作为更高效的方法来检索值,如果程序必须经常尝试在已排序的列表中,不必显示如何使用ContainsKey方法来测试某个键是否存在之前调用Add方法。

 关于SortedList<TKey,TValue>,SortedDictionary<TKey,TValue>使用出现的问题

其键不允许重复。使用SortedSet<T>进行解决。

 

参考:

https://github.com/dotnet/platform-compat/blob/master/docs/DE0006.md

上一篇:ASP.NET MVC


下一篇:mysql使用传输表空间对大表或分区表进行快速复制