List的可比及深入分析

C#的集合类命名空间介绍:

一. Dictionary与Hashtable

Dictionary与Hashtable都以.Net
Framework中的字典类,可以基于敏捷搜索

两岸的特征轮廓上是一模二样的,一时能够把Dictionary<K,V>看做是Hashtable的泛型版本。可是Hashtable是线程安全的,Dictionary是上行下效的。

字典的品质取决于键类型的GetHashCode()方法的兑当代码。

键类型也无法不贯彻IEquatable<T>.Equals()方法,并且只要A.Equals(B)重回true,则A和B的GetHashCode()也必得回到一样的值。

 

Dictionary

  • 有泛型优势(类型安全,质量更加好),对于值类型,不设有装箱和拆箱的习性损耗
  • 读取速度快(突显在单条数据上)
  • 容积利用更充裕
  • 有序(遍历时输出的逐一正是加盟的依次)

Hashtable

  • 切合二十八线程
  • 通过静态方法Synchronize方法可获取完全线程安全的项目
  • 无序

 

// 程序集
mscorlib.dll
System.dll
System.Core.dll
// 命名空间
using System.Collections:集合的接口和类
using System.Collections.Generic:泛型集合的接口和类,强类型安全
using System.Collections.Specialized:专用的和强类型的集合 
using System.Collections.Concurrent:线程安全的集合 

二.List与Dictionary

List有一些类似于Dictionary。二者都享有应用泛型的独到之处,Dictionary未有在内部存款和储蓄器中移动继续成分的属性开支。

List是在数组的底子上做的卷入,遍历查询更加快(数据相当多时),Dictionary单条查询越来越快

援用某一篇著作的分析:

style=”font-size: 13px;”>同样是集合,为什么性能会有这样的差距。我们要从存储结构和操作系统的原理谈起。 style=”font-size: 13px;”> 

style=”font-size: 13px; color: #808080;”>首先我们清楚List<T>是对数组做了一层包装,我们在数据结构上称之为线性表,而线性表的概念是,在内存中的连续区域,除了首节点和尾节点外,每个节点都有着其唯一的前驱结点和后续节点。我们在这里关注的是连续这个概念。

style=”font-size: 13px; color: #808080;”>而HashTable或者Dictionary,他是根据Key和Hash算法分析产生的内存地址,因此在宏观上是不连续的,虽然微软对其算法也进行了很大的优化。

style=”font-size: 13px; line-height: 1.5; color: #808080; background-color: initial;”>由于那样的不总是,在遍历时,Dictionary必然会生出一大波的内部存款和储蓄器换页操作,而List只须求开展最少的内部存储器换页就能够,那就是List和Dictionary在遍历时成效差距的根本原因。

 

style=”font-size: 13px;”>6. 再谈Dictionary style=”font-size: 13px;”> 

style=”font-size: 13px;”>也许很多人说,既然Dictionary如此强大,那么我们为什么不用Dictionary来代替一切集合呢? style=”font-size: 13px;”> 

style=”font-size: 13px;”>在这里我们除了刚才的遍历问题,还要提到Dictionary的存储空间问题,在Dictionary中,除了要存储我们实际需要的Value外,还需要一个辅助变量Key,这就造成了内存空间的双重浪费。 style=”font-size: 13px;”> 

style=”font-size: 13px;”>而且在尾部插入时,List只需要在其原有的地址基础上向后延续存储即可,而Dictionary却需要经过复杂的Hash计算,这也是性能损耗的地方。 style=”line-height: 1.5; background-color: initial;”> 

 

 

粗略的做了下测量检验

爱博体育app手机版 1爱博体育app手机版 2

using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp
{
    class Program
    {
        public const int TOTAL_COUNT = 1000000;

        public static void Main(string[] args)
        {
            ListTest();
            DicTest();
            HashtableTest();
            ListInsertTest();
        }

        private static void HashtableTest()
        {
            Hashtable ht = new Hashtable();
            for (int i = 0; i < TOTAL_COUNT; i++)
            {
                ht.Add(i, new Model { Num = i });
            }
        }

        public static void ListTest()
        {
            List<Model> list = new List<Model>();
            for (int i = 0; i < TOTAL_COUNT; i++)
            {
                list.Add(new Model { Num = i });
            }
        }
        public static void ListInsertTest()
        {
            List<Model> list = new List<Model>();
            list.Insert(0, new Model { Num = 0 });
            list.Insert(1, new Model { Num = 1 });
            for (int i = 2; i < TOTAL_COUNT; i++)
            {
                list.Insert(1,new Model { Num = i });
            }
        }

        public static void DicTest()
        {
            Dictionary<int, Model> dic = new Dictionary<int, Model>();
            for (int i = 0; i < TOTAL_COUNT; i++)
            {
                dic.Add(i, new Model { Num = i });
            }
        }

        public class Model
        {
            public int Num { set; get; }
        }
    }
}

测量检验代码

 

其一测量试验总共有八个插入数据情势:Hashtable.Add,Dictionary.Add,List.Add,List.Insert

字典中插入的Key都是int类型。 结果如下

爱博体育app手机版 3

 

艺术中插入次数都以100W  因为实际等不下来了,就中途甘休了。

只是那基本不影响深入分析结果,因为拖后腿的是List.Insert,在只进行了28W的情事下就早已占到了总耗费时间的95%。

从结果中得以观察插入功能依次是 List.Add
-> Dictionary.Add -> Hashtable.Add -> List.Insert

以此结果也符合地方的解析。

 

上边在实地衡量一下遍历

爱博体育app手机版 4爱博体育app手机版 5

using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        public const int TOTAL_COUNT = 1000000;

        public static void Main(string[] args)
        {
            List<Model> list = new List<Model>();
            for (int i = 0; i < TOTAL_COUNT; i++)
            {
                list.Add(new Model { Num = i });
            }

            Hashtable ht = new Hashtable();
            for (int i = 0; i < TOTAL_COUNT; i++)
            {
                ht.Add(i,new Model { Num = i });
            }

            Dictionary<int, Model> dic = list.ToDictionary(l=>l.Num);

            ListTest(list);
            DicTest(dic);
            HashtableTest(ht);
        }

        private static void HashtableTest(Hashtable ht)
        {
            foreach (var key in ht.Keys)
            {
                var rst = ht[key];
            }
        }

        public static void ListTest(List<Model> list)
        {
            foreach (var item in list)
            {
                var rst = item;
            }
        }

        public static void DicTest(Dictionary<int, Model> dic)
        {
            foreach (var key in dic.Keys)
            {
                var rst = dic[key];
            }
        }

        public class Model
        {
            public int Num { set; get; }
        }
    }
}

遍历测量试验代码

 

还是100W条数据

爱博体育app手机版 6

 

List -> Dictionary -> Hashtable

 

 

相关文章:Dictionary<T1,T2>和List<T>哪个作用越来越好

 

 

会集基于ICollection接口、IList接口、IDictionary接口及其泛型接口版本、IEnumerable接口及其泛型版本,当中接口IList和IDictionary均从ICollection接口和IEnumerable接口派生,由此具备集合全部一直或直接基于ICollection接口和IEnumerable接口:

  • 泛型IEnumerable接口承接IEnumerable接口,IEnumerable接口无父接口;
  • 泛型ICollection接口传承泛型IEnumerable接口和IEnumerable接口,ICollection接口承袭IEnumerable接口;
  • 抱有会集均贯彻IEnumerable接口,泛型集合均落到实处IEnumerable<T>接口;
  • 具备会集(除StringDictionary、HashSet<T>)均实现ICollection接口,泛型集合(除Stack<T>、Queue<T>)均落到实处ICollection<T>接口;

:集结是或不是落实ICollection接口及其泛型版本,注意两个的接口定义就可以。

  • IEnumerable – IEnumerable<T>:扶助枚举器;
  • IList、IList<T>:协助索引访问;
  • IDictionary、IDictionary<T>:协助键值访谈;

有关字典集的枚举访谈

  • 非泛型字典集类(除StringDictionary、NameValueCollection是平凡的枚举器直接重返会集成分)枚举时重临DictionaryEntry对象:

    foreach (DictionaryEntry de in myXxx) {

    Console.WriteLine(de.Key, + ": " + de.Value);
    

    } 

  • 泛型字典集类枚举时再次回到KeyValuePair对象:

    foreach (KeyValuePair kvp in myGenericXxxDic){

    Console.WriteLine(kvp.Key + ": " + kvp.Value);
    

    }

参考

ICollection – ICollection<T>

style=”font-size: 16px;”>ICollection爱博体育app手机版,:全体非泛型集结的分寸、枚举器和共同方法

public interface ICollection : IEnumerable {
    int Count { get; }
    bool IsSynchronized { get; } // 对ICollection的访问是否是同步的(线程安全)
    object SyncRoot { get; } // 获取可用于对ICollection同步访问的对象
    void CopyTo(Array array, int index);
}

style=”font-size: 16px;”>ICollection<T>:泛型会集的属性方法

public interface ICollection<T> : IEnumerable<T>, IEnumerable {
    int Count { get; }
    bool IsReadOnly { get; }
    void Add(T item);
    bool Remove(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
}

爱博体育app手机版 7

注:使用可变集合时,若不点名initCapacity,系统会选用私下认可的initCapacity。当成分个数超越initCapacity时,先在中间重新创设(二倍扩大)一个集中,再将原集结中的成分复制到新集结中。提议实例化可变群集时钦定贰个对峙比较大的initCapacity,制止在向可变集结中丰富大量因素时因聚焦扩充容积带来的性质损失。

数组:Array – ArrayList – List<T>

实为是数组实现、援助索引访谈。四个类都达成IList接口,List<T>泛型类还落到实处IList<T>泛型接口,List<T>是ArrayList对应的泛型版本达成。

参考:.net会集类的钻研–Array,
ArrayList,
List<T>

style=”font-size: 16px; color: #ff6600;”>Array:抽象类,提供属性和艺术操作(创立、寻觅、排序)数组,用作全数数组的基类

数组是具备同等档期的顺序的八个指标的联谊,全体数组均承袭System.Array类。类型安全、非线程安全。

  • 长度固定,不可能伸缩,但数组可有多少个维度;
  • 可读可写,但不能够声称只读数组;
  • 辅助下标索引访谈,三遍得到或设置二个成分的值;
  • 数组必得证明成分的花色;

抽象类,不可能使用构造函数创制数组,可是可以通过Array类的静态方法CreateInstance()创建数组:

// 创建索引从0开始、具有指定System.Type和长度的一维System.Array
public static Array CreateInstance(Type elementType, int length);

C# – Array类代码  

对此数据类型一致和容积固定的景观,首要推荐数组、品质高,且数组存款和储蓄数据对GC友好。

public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable {
    public int Length { get; }
    public long LongLength { get; }  // 64位长度
    public int Rank { get; }  // 维数(秩)
    public object SyncRoot { get; }
    public bool IsSynchronized { get; }
    public bool IsReadOnly { get; }

    public static Array CreateInstance(Type elementType, int len);  // 创建Array实例
    public void Initialize(); // 调用值类型的默认构造函数,初始化Array的元素
    public object Clone();    // 浅表副本
    public static ReadOnlyCollection<T> AsReadOnly<T>(T[] arr); // 返回指定数组的只读版本
    public static void Clear(Array array, int index, int length);
    public static void Resize<T>(ref T[] arr, int newSize);  // 重置数组大小
    // 指定维度的长度、下界、上界
    public int GetLength(int dimension);
    public int GetLower/UpperBound(int dimension);
    public static int BinarySearch(XXX xxx);
    public static int Sort(XXX xxx);
    public static void Reverse(Array arr [, int idx, int len]);
    public object Get/SetValue(int index);
    public static int IndexOf(Array array, object value);
    public static int LastIndexOf(Array array, object value);
    public static void Copy(Array srcArr, Array destArr, int len);
    public void CopyTo(Array array, int index);
    public IEnumerator GetEnumerator();  // 枚举器

    // 函数式编程
    public static void ForEach<T>(T[] array, Action<T> action); // 对指定数组的每个元素执行指定操作
    public static bool Exists<T>(T[] array, Predicate<T> match);
    public static T Find<T>(T[] array, Predicate<T> match);
    public static T FindLast<T>(T[] array, Predicate<T> match);
    public static T[] FindAll<T>(T[] array, Predicate<T> match);
    public static int FindIndex<T>(T[] arr, [int startIdx, int cnt,] Predicate<T> match);
    public static int FindLastIndex<T>(T[] arr, [int startIdx, int cnt,] Predicate<T> match);
}

style=”font-size: 16px; color: #ff6600;”>ArrayList: 使用大小可按需动态增添的数组完成IList接口

动态数组,Array的繁杂版本(ArrayList是对Array的包装,实际多少操作依然针对Array)、速度略慢,针对任意等级次序的成分(可为null)、放肆长度,非类安全型、非线程安全。

原理达成

ArrayList内部维护三个数组,内置_items数组暗许长度为4:

private object[] _items;
private static readonly object[] emptyArray = new object[0];  // 用于初始化数组_items
private const int _defaultCapacity = 4;

初始化ArrayList:

爱博体育app手机版 8

ArrayList扩容:

爱博体育app手机版 9

选拔示例

ArrayList myArrayList = new ArrayList();
Object obj = null; myArrayList.Add(obj);  // 元素类型为Object,可为null
myArrayList.Add(null);   // 元素可为空null
myArrayList.Add(null);   // 空null可重复添加 

线程安全性

里头类SyncArrayList是承继ArrayList类的私有类,通过lock同步构造lock(this._root)完成线程安全。

  • SyncRoot属性

爱博体育app手机版 10

  • Synchronized()方法

    ArrayList mySyncArrayList = ArrayList.Synchronized(myArrayList); 

爱博体育app手机版 11

C#-ArrayList类代码

public class ArrayList : IList, ICollection, IEnumerable, ICloneable {
    public virtual int Capacity { get; set; }
    public virtual int Count { get; } 
    public virtual bool IsReadOnly { get; }
    public virtual bool IsSynchronized { get; } 
    public virtual object SyncRoot { get; } 
    public virtual object this[int index] { get; set; }  // 索引访问器

    public ArrayList();
    public ArrayList(int capacity);
    public ArrayList(ICollection c);
    public virtual IEnumerator GetEnumerator([int idx, int cnt]); // 枚举器
    public virtual object Clone(); // 创建ArrayList的浅表副本
    public virtual ArrayList GetRange(int idx, int cnt); // 子集
    public virtual void SetRange(int idx, ICollection c); // 设置ArrayList的值
    public static ArrayList ReadOnly(ArrayList list); // 返回只读的ArrayList包装
    public static IList ReadOnly(IList list); // 返回只读的IList包装
    public static ArrayList Synchronized(ArrayList list); // 返回线程同步的ArrayList包装
    public static IList Synchronized(IList list); // 返回线程同步的IList包装
    public static ArrayList Adapter(IList list);  // 返回IList的ArrayList包装
    public virtual int Add(object val);
    public virtual void AddRange(ICollection c);
    public virtual void Insert(int idx, object val);
    public virtual void InsertRange(int idx, ICollection c);
    public virtual void Remove(object obj);
    public virtual void RemoveAt(int idx);
    public virtual void RemoveRange(int idx, int cnt);
    public virtual void Clear();
    public virtual bool Contains(object item);
    public virtual int IndexOf(object val [, int startIdx, int cnt]);
    public virtual int LastIndexOf(object val [, int startIdx, int cnt]);
    public virtual void Reverse([int idx, int cnt]); // 反转
    public virtual void Sort([IComparer cmp]);       // 排序
    public virtual int BinarySearch(object val [, IComparer cmp]); // 二分查找
    public virtual object[] ToArray();
    public virtual void CopyTo(Array array [, int arrayIdx]);
}

其中,接口IList代表对象的非泛型集合,可根据索引单独访谈  

public interface IList : ICollection, IEnumerable {
    bool IsReadOnly { get; }
    object this[int index] { get; set; }  // 索引器:获取或设置指定索引处的元素

    int Add(object value);
    void Insert(int index, object value);
    void Remove(object value);
    void RemoveAt(int index);
    void Clear();
    bool Contains(object value);
    int IndexOf(object value);
}

style=”font-size: 16px;”>List<T>:对象的强类型列表,可因此索引访谈的。提供寻觅、排序和操作列表的不二秘技

泛型,List<T>也是对Array的包裹,实际多少操作依旧针对Array,类型安全、非线程安全。 

参考:.NET,你忘掉了么?(三续)——重新领略List<T>
 .net源码深入分析 –
List
<T>

原理实现

List<T>内部维护四个数组,内置_items数组默许长度为4:

private object[] _items;
private static readonly T[] _emptyArray = new T[0];
private const int _defaultCapacity = 4;

初始化List<T>:

爱博体育app手机版 12

List<T>扩容:同ArrayList。

使用示例

List<string> myList = new List<string>();
string str = null;   myList.Add(str);  // 元素类型为string,可为null
myList.Add(null);   // 元素可为空null
myList.Add(null);   // 空null可重复添加

C#-List<T>类代码 

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable {
    public int Count { get; }
    public int Capacity { get; set; }
    public T this[int index] { get; set; }  // 索引访问器

    public List();
    public List(int capacity);
    public List(IEnumerable<T> collection);
    public void Add(T item);
    public void AddRange(IEnumerable<T> collection);
    public void Insert(int index, T item);
    public void InsertRange(int index, IEnumerable<T> collection);
    public bool Remove(T item);
    public void RemoveAt(int index);
    public void RemoveRange(int index, int count);
    public void Clear();
    public bool Contains(T item);
    public int IndexOf(T item [, int idx, int cnt]);
    public int LastIndexOf(T item [, int idx, int cnt]);
    public int BinarySearch(T item);
    public int BinarySearch(T item, IComparer<T> comparer);
    public void Sort();
    public void Sort(Comparison<T> comparison);
    public void Sort(IComparer<T> comparer);
    public void Reverse();
    public void Reverse(int index, int count);
    public List<T> GetRange(int index, int count);
    public T[] ToArray();
    public void CopyTo(T[] array [, int arrayIndex]);
    // 枚举器
    public List<T>.Enumerator GetEnumerator();
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator

    // 支持函数式编程
    public void ForEach(Action<T> action);
    public bool Exists(Predicate<T> match);
    public T Find(Predicate<T> match);
    public T FindLast(Predicate<T> match);
    public int FindIndex([int startIdx, int cnt, ] Predicate<T> match);
    public int FindLastIndex([int startIdx, int cnt, ] Predicate<T> match);
    public List<T> FindAll(Predicate<T> match);
    public int RemoveAll(Predicate<T> match);
    public bool TrueForAll(Predicate<T> match); // 每个元素是否与指定的谓词条件匹配
}

中间, public delegate bool Predicate<in T>(T obj); 表示定义一组条件并规定钦定对象是不是切合那么些条件的法子。

其中,接口IList**<T**>代表可根据索引单独访谈的一组对象的集合 

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable {
    T this[int index] { get; set; }   // 索引器:获取或设置指定索引处的元素
    void Insert(int index, T item);
    void RemoveAt(int index);
    int IndexOf(T item);
}  

参考:ArrayList 和 List 集结类型 –
msdn
.aspx);

哈希表:Hashtable – Dictionary<TKey, TValue>

精神是哈希表完结、辅助键值访问。五个类都落到实处IDictionary接口,Dictionary<TK,
电视机>泛型类还实现IDictionary<TK, TV>泛型接口,Dictionary<TK,
电视机>是Hashtable对应的泛型版本达成。

参考:

style=”font-size: 16px; color: #ff6600;”>Hashtable:依照键的哈希代码举行共青团和少先队的键/值对聚焦

精神是哈希表达成(单一数组)、协助键值访问。每一种成分都以叁个积攒在DictionaryEntry对象中的键值对。Hashtable对象由富含集合元素的存款和储蓄桶组成,每一个仓库储存桶与三个Hash代码关联,通过键检索值实质是检索键对应的Hash代码(调用GetHashCode()方法总结当前键的hash值)关联的寄存桶。keyvalue键值对均为object类型,匡助其余类型的keyvalue键值对,但键不可为null且键不容许再次,查找速度快临近O(1),但内部存款和储蓄器占用大、利用率低,空间换时间。非类安全型、线程安全。

哈希表内部贯彻存取的数组的尺寸总是四个素数,成立大概二倍扩张Hashtable时体积一般会偏大,而且加载因子(暗中认可0.72f)的存在,Hashtable在未存满的景况下将在庞大。Hashtable内部维护贰个bucket类型的数组变量,bucket是四个结构,用来保存Key,Value和哈希值

private struct bucket {
    public object key;
    public object val;
    public int hash_coll;
}

其中,hash_coll的最高位表示近来职责是否爆发冲突,“0”(正数)表示未爆发争论、“1”(负数)表示最近岗位龃龉,特地选取标记位标记是或不是发生争辩能够增长哈希表的运作功用。

规律完成

Hashtable内部维护八个数组,内置buckets数组的长短暗中同意钦命为3:

private Hashtable.bucket[] buckets;
private const int InitialSize = 3;
private float loadFactor;

初始化Hashtable:

爱博体育app手机版 13

其中,GetPrime()方法会在扩大体积时回来略大于原数组双倍大小的三个素数,作为新数组的分寸:

爱博体育app手机版 14

其中,primes[]是.NET内部维护的二个素数数组,制止生成素数时的额外成本。

Hashtable扩容:

爱博体育app手机版 15

中间,rehash()方法的入参bool
forceNewHashCode设置为false,注明扩大体积时没有要求再度总结hashcode,不过取模运算和要素地点的重新分配是必得的:

爱博体育app手机版 16

运用示例

Hashtable myHashtable = new Hashtable(20);
Object key = null, val = null; myHashtable.Add(key,val);  // error,键/值均为Object类型,但键不能为null
myHashtable.Add(null,null);  // error,键不能为null

遍历Hashtable元素

// 方法一
foreach (DictionaryEntry de in myHashtable) {     
    Console.WriteLine("Key: {0}, Value: {1}", de.Key, de.Value);
}
// 方法二
IDictionaryEnumerator iDe = myHashtable.GetEnumerator();    
    while (iDe.MoveNext()) {
        Console.WriteLine("Key: {0}, Value: {1}", iDe.Key, iDe.Value);
}

排序Hashtable元素

ArrayList tmpKeysArrayList = new ArrayList(myHashtable.Keys);
tmpKeysArrayList.Sort();
foreach (var tmpKey in tmpKeysArrayList) {
    Console.WriteLine("Key: {0}, Value: {1}", tmpKey, myHashtable[tmpKey]);
}

线程安全

其间类SyncHashtable是一连Hashtable类的私有类,通过lock同步构造lock(this._table.SyncRoot)实现线程安全,个中SyncRoot是Hashtable的公有属性。完结格局与ArrayList一模一样。多线程并发,同不经常刻只能有三个线程写、别的阻塞,对读的线程不受影响。

  • SyncRoot属性    同ArrayList。
  • Synchronized()方法

    // 方法一
    Hashtable mySyncHashtable = Hashtable.Synchronized(myHashtable);
    // 方法二
    lock (myHashtable.SyncRoot) { try{…} catch(){…} }
    // 方法三
    Monitor.Enter(myHashtable.SyncRoot);
    try{…} catch(){…}
    Monitor.Exit(myHashtable.SyncRoot);      

爱博体育app手机版 17

C#-Hashtable类代码 

public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable {
    public virtual int Count { get; }
    public virtual bool IsReadOnly { get; }
    public virtual bool IsSynchronized { get; }
    public virtual object SyncRoot { get; }
    public virtual ICollection Keys { get; }
    public virtual ICollection Values { get; }
    public virtual object this[object key] { get; set; }  //键值访问器
    protected IComparer comparer { get; set; }  // 返回IComparer对象,用于比较

    public Hashtable();
    public Hashtable(int capacity);
    public Hashtable(IDictionary d);
    public virtual IDictionaryEnumerator GetEnumerator(); // 枚举器
    public virtual object Clone(); // 创建Hashtable的浅表副本
    public static Hashtable Synchronized(Hashtable table); // 返回线程同步的Hashtable包装
    public virtual void Add(object key, object value);
    public virtual void Remove(object key);
    public virtual void Clear();
    public virtual bool Contains(object key);
    public virtual bool ContainsKey(object key);
    public virtual bool ContainsValue(object value);
    protected virtual int GetHash(object key);
    protected virtual bool KeyEquals(object item, object key); // 与键比较
    public virtual void CopyTo(Array array, int arrayIndex);
}

其中,接口IDictionary表示键/值对的非泛型集结

public interface IDictionary : ICollection, IEnumerable {
    bool IsReadOnly { get; }
    Object this[Object key] { get; set; }  // 键值访问器
    ICollection Keys { get; }
    ICollection Values { get; }

    void Add(object key, object value);
    void Remove(object key);
    void Clear();
    bool Contains(object key);
    IDictionaryEnumerator GetEnumerator();
}

其中,IDictionaryEnumerator意味着非泛型字典集的枚举器

public interface IDictionaryEnumerator : IEnumerator {
    DictionaryEntry Entry { get; }
    object Key { get; }
    object Value { get; }
}

其中,DictionaryEntry代表字典集的要素(键/值对)  

public struct DictionaryEntry {
    public DictionaryEntry(object key, object value);
    public object Key { get; set; }
    public object Value { get; set; }
}

参考:

Dictionary<TKey,
TValue>
:键值对的泛型集结 

精神是哈希表(数组+链表数组)、提供便捷的依附键值的要素查找。Dictionary<[key],
[value]>,键必需独一且无法为空null,值若为援引类型则可为空,类型安全、非线程安全。

参考:.net源码剖析 –
Dictionary<TKey,
电视机alue>

规律完结

Dictionary<TK, TV>在其间维护四个数组:

private int[] buckets;
private Dictionary<TKey, TValue>.Entry[] entries;  // 链表数组
  • 平时数组buckets:寄放由八个同义词组成的静态单链表的头指针(单链表的首先个因素在entries数组中的索引号),当buckets[i]=-1(头指针=null)时表示此哈希地址最近荒诞不经成分;
  • 链表数组entries:寄存哈希表中的实际数据,数据通过next指针构成五个单链表;

链表数组entries是八个Entry类型的数组变量,Entry是二个结构,用来保存Key、Value和哈希值:

private struct Entry {
    public int hashCode;
    public int next;  // (链接法,指向下一个结点)
    public TKey key;
    public TValue value;
}

因为Dictionary<TK,
电视>选择分离链接法存款和储蓄成分,不受装填因子的范围(默许1.0f),链表数组entries也设有三遍扩大体量的难点、可是扩大体积代价小于Hashtable。查找操作若要求遍历单链表会形成品质损耗、且链表对GC未有数组友好。

初始化Dictionary<TK, TV>:

爱博体育app手机版 18

安顿操作:Dictionary<TK,
电视>的Add()方法会调用内部的Insert()方法,具体:

爱博体育app手机版 19

Dictionary<TK, 电视>扩大体量:通过Resize()方法完毕,入参bool
forceNewHashCode设置为false,注脚无需再行总结hashcode,然而取模运算和要素地方的重新分配是必得的。

爱博体育app手机版 20

其中,GetPrime()和ExpandPrime()方法同Hashtable。三次扩大体量不要求重新哈希。

选择示例

Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("", null);     // 正确,值为引用类型时,允许为空null
myDictionary.Add(null, null);  // error,键不能为空null

遍历Dictionary<K,V>元素

// 方法一:By KeyValuePair 
foreach (KeyValuePair<T1, T2> kvp in myDictionary)  或  foreach(var kvp in myDictionary)
// 方法二:By Key
Dictionary<T1, T2>.KeyCollection keyCollection = myDictionary.Keys;
foreach (T1 key in keyCollection)  或  foreach(T1 key in myDictionary.Keys)  
// 方法三:By Value
Dictionary<T1, T2>.ValueCollection valueCollection = myDictionary.Values;
foreach (T2 val in valueCollection)  或  foreach(T2 val in myDictionary.Values) 
// 方法四:By IEnumerator
Dictionary<TK, TV>.Enumerator myIE = myDictionary.GetEnumerator();
while (myIE.MoveNext()) {
    Console.WriteLine(myIE.Current.Key + ": " + myIE.Current.Value);
} 

TryGetValue()

得到与钦点的键相关联的值,制止因获取不到相应的值发生格外。通过键取值,富含五个参数,一个是要查询的键,另多少个是获取的值,注意值前边使用out关键字,不然编写翻译失利。

public bool TryGetValue(TK key, out TV val);

:“剖断键存在”和“根据键取值”两步转化为一步,键的哈希值只总结一次,作用高,时间复杂度临近O(1)。

C#-Dictionary<TKey,
TValue>类代码
 

public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback {
    public int Count { get; }
    public Dictionary<TKey, TValue>.KeyCollection Keys { get; }
    public Dictionary<TKey, TValue>.ValueCollection Values { get; }
    public TValue this[TKey key] { get; set; }  // 键值访问器

    public Dictionary();
    public Dictionary(int capacity);
    public Dictionary(IDictionary<TKey, TValue> dictionary);
    public Dictionary<TKey, TValue>.Enumerator GetEnumerator(); // 枚举器
    public void Add(TKey key, TValue value);
    public bool Remove(TKey key);
    public void Clear();
    public bool ContainsKey(TKey key);
    public bool ContainsValue(TValue value);   
    public bool TryGetValue(TKey key, out TValue value);

    public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator {}
    public sealed class KeyCollection : ICollection<TKey>, IEnumerable<TKey>, ICollection, IEnumerable {}
    public sealed class ValueCollection : ICollection<TValue>, IEnumerable<TValue>, ICollection, IEnumerable {}
}

其中,接口IDictionary<TKey,
TValue>
意味着键/值对的泛型集结  

public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable {
    TValue this[TKey key] { get; set; }  // 键值访问器
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }

    void Add(TKey key, TValue value);
    bool Remove(TKey key);
    bool ContainsKey(TKey key);
    bool TryGetValue(TKey key, out TValue value);
} 

其中,KeyValuepair概念可安装或探索的键/值对:

public struct KeyValuePair<TKey, TValue> {
    public KeyValuePair(TKey key, TValue value);
    public TKey Key { get; }
    public TValue Value { get; }
    public override string ToString();
}  

参考:

 


上面部分是有关有序字典集及片段专项使用字典集

爱博体育app手机版 21

逐步字典集:SortedList – SortedList<TK, 电视> – SortedDictionary<TK, TV>

四个类都落到实处IDictionary接口,三个泛型类还完成IDictionary<TK,
电视机>泛型接口,SortedList<TK, 电视>和SortedDictionary<TK,
TV>是Dictionary<TK, 电视机>的排序版本达成,SortedDictionary<K,
V>提供比Dictionary<K,
V>越来越快的检索速度。非泛型SortedList类枚举时重临DictionaryEntry指标,三个泛型类枚举时重返KeyValuePair对象。

SortedList、SortedList**<T**>双数组达成(本质照旧数组)、帮助索引访谈和键值访问,SortedDictionary红黑树完毕(二叉平衡树)、辅助键值访问

参考:

style=”color: #ff6600; font-size: 16px;”>SortedList:开关排序的键/值对聚焦,可按钮和目录访问

双数组达成、协理索引,在内部维护五个数组用于存款和储蓄列表中的成分:贰个数组用于键,二个数组用于相关联的值。键无法为空null、值可认为null。由于排序,SortedList质量略差于Hashtable。非类型安全、非线程安全。

原理落成

SortedList内部维护七个数组:二个键数组和二个值数组。SortedList集合的骨干:二分查找法的应用。

private object[] keys;
private object[] values;
private static object[] emptyArray = new object[0];  // 用于初始化数组keys和values
private const int _defaultCapacity = 16;

初始化SortedList:

爱博体育app手机版 22

SortedList扩大体积:同样存在一次扩大体积难点,代码同ArrayList/List<T>,私下认可_defaultCapacity =
16。

C#-SortedList类代码

public class SortedList : IDictionary, ICollection, IEnumerable, ICloneable {
    public virtual int Capacity { get; set; }
    public virtual int Count { get; }
    public virtual bool IsReadOnly { get; }
    public virtual bool IsSynchronized { get; }
    public virtual object SyncRoot { get; }
    public virtual ICollection Keys { get; }
    public virtual ICollection Values { get; }
    public virtual object this[object key] { get; set; }  // 键值访问器

    // 未指定IComparer比较器的SortedList,根据键实现的System.IComparable接口排序
    public SortedList();
    public SortedList(int initCapacity);
    public SortedList(IDictionary d);
    public SortedList(IComparer comparer);
    public virtual object Clone();  // 创建SortedList对象的浅表副本
    public virtual IDictionaryEnumerator GetEnumerator(); // 枚举器
    public static SortedList Synchronized(SortedList list);
    public virtual void Add(object key, object value);
    public virtual void Remove(object key);
    public virtual void RemoveAt(int index);
    public virtual void Clear();
    public virtual bool Contains(object key);
    public virtual bool ContainsKey(object key);
    public virtual bool ContainsValue(object value);
    public virtual object GetByIndex(int index);
    public virtual void SetByIndex(int index, object value);
    public virtual object GetKey(int index);
    public virtual IList GetKeyList();
    public virtual IList GetValueList();
    public virtual int IndexOfKey(object key);
    public virtual int IndexOfValue(object value);
    public virtual void CopyTo(Array array, int arrayIndex);
}

SortedList<TK,
TV>
:基于关联的System.Collections.Generic.IComparer<T>完成的按钮排序的键/值对会集 

具有O(logN)检索的二进制寻觅树,双数组实现、协助索引。类型安全、非线程安全。

原理完成

SortedList<TK,
电视>内部维护四个数组:二个键数组和贰个值数组,与SortedList一模二样。

private TKey[] keys;
private TValue[] values;
private static TKey[] emptyKeys = new TKey[0];
private static TValue[] emptyValues = new TValue[0];
private const int _defaultCapacity = 4;

初始化SortedList<TK, TV>:

爱博体育app手机版 23

SortedList扩大体量:一样存在一次扩大体积难点,代码同ArrayList/List<T>,暗中认可_defaultCapacity =
4。

C#-SortedList<TK,
TV>类代码
 

public class SortedList<TK, TV> : IDictionary<TK, TV>, ICollection<KeyValuePair<TK, TV>>, IEnumerable<KeyValuePair<TK, TV>>, IDictionary, ICollection, IEnumerable {
    public int Count { get; }
    public int Capacity { get; set; }
    public IList<TK> Keys { get; }
    public IList<TV> Values { get; }
    public TV this[TK key] { get; set; }    // 键值访问器
    public IComparer<TK> Comparer { get; }  // 比较器

    public SortedList();
    public SortedList(int capacity);  
    public SortedList(IDictionary<TK, TV> dictionary);
    public SortedList(IComparer<TK> comparer);
    public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator();  // 枚举器
    public void Add(TK key, TV val);
    public bool Remove(TK key);
    public void RemoveAt(int index);
    public void Clear();
    public bool ContainsKey(TK key);
    public bool ContainsValue(TV val);
    public int IndexOfKey(TK key);
    public int IndexOfValue(TV value);
    public bool TryGetValue(TK key, out TV value);
}

style=”color: #ff6600; font-size: 16px;”>SortedDictionary<TKey,
TValue>
:按钮排序的键/值对集中

SortedDictionary<TK, TV>通过TreeSet<T>完毕,TreeSet<T>承袭SortedSet<T>,SortedSet<T>是红黑树完成,不支持索引、具有O(logN)检索的二进制搜索树。类型安全、非线程安全。

规律完成

SortedDictionary<TK,
电视>内部维护叁个TreeSet<T>变量(结点类型是KeyValuePair<TK,
TV>):

private TreeSet<KeyValuePair<TKey, TValue>> _set;  

C#-SortedDictionary<TK,
TV>类代码

public class SortedDictionary<TK, TV> : IDictionary<TK, TV>, ICollection<KeyValuePair<TK, TV>>, IEnumerable<KeyValuePair<TK, TV>>, IDictionary, ICollection, IEnumerable {   
    public int Count { get; }
    public SortedDictionary<TK, TV>.KeyCollection Keys { get; }
    public SortedDictionary<TK, TV>.ValueCollection Values { get; }
    public TValue this[TKey key] { get; set; }  // 键值访问器
    public IComparer<TK> Comparer { get; }  // 比较器

    public SortedDictionary();
    public SortedDictionary(IDictionary<TK, TV> dictionary);
    public SortedDictionary(IComparer<TK> comparer);
    public void Add(TK key, TV value);
    public bool Remove(TK key);
    public void Clear();
    public bool ContainsKey(TK key);
    public bool ContainsValue(TV value);
    public bool TryGetValue(TKey key, out TValue value);
    public void CopyTo(KeyValuePair<TK, TV>[] array, int index);

    public SortedDictionary<TK, TV>.Enumerator GetEnumerator();  // 枚举器
    public struct Enumerator : IEnumerator<KeyValuePair<TK, TV>>, IDisposable, IDictionaryEnumerator, IEnumerator {}
    public sealed class KeyCollection : ICollection<TK>, IEnumerable<TK>, ICollection, IEnumerable {}
    public sealed class ValueCollection : ICollection<TV>, IEnumerable<TV>, ICollection, IEnumerable {}
}

参考:SortedList 和
SortedDictionary 集结类型 –
msdn
.aspx);

字典集其余部分:System.Collections.Specialized

ListDictionary、HybridDictionary、OrderedDictionary几个类均落到实处了IDictionary接口、支持键值访谈,StringDictionary仅达成了IEnumerable接口、不过补助键值访问。

style=”color: #ff6600;”>ListDictionary:使用单链接列表达成IDictionary,适于小会集(<10)

实质是链表落成、帮忙键值访谈。链表插入/删除方便,节省外部存款和储蓄器空间、不设有空间浪费的难点,可是Add()方法须求遍历链表、效能低。对于小集合,ListDictionary比Hashtable快。

原理实现

ListDictionary内部维护多个单链表:

private ListDictionary.DictionaryNode head;  // 单链表头指针

ListDictionary不真实三回扩容的难题,不过ListDictionary在增多新数据时,Add()方法要遍历链表(找到尾结点):

爱博体育app手机版 24

C# – ListDictionary类代码

public class ListDictionary : IDictionary, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsReadOnly { get; }
    public bool IsSynchronized { get; }
    public object SyncRoot { get; }
    public ICollection Keys { get; }    
    public ICollection Values { get; }
    public object this[object key] { get; set; }   // 键值访问器
    public IDictionaryEnumerator GetEnumerator();  // 枚举器

    public ListDictionary();
    public ListDictionary(IComparer comparer);
    public void Add(object key, object value);
    public void Remove(object key);
    public void Clear();
    public bool Contains(object key);
    public void CopyTo(Array array, int index);
} 

当中,单链表结点DictionaryNode

private class DictionaryNode{
    public object key;
    public object value;
    public ListDictionary.DictionaryNode next;
}

style=”color: #ff6600; font-size: 16px;”>HybridDictionary:集结极小时,使用ListDictionary落成IDictionary,集合变大时,切换成Hashtable  

支持键值访谈。结合了ListDictionary(占用内部存款和储蓄器空间少)和Hashtable(查询效能高)的独到之处。 

规律完毕

HybridDictionary在当中维护一个ListDictionary链表和一个Hashtable变量:

private ListDictionary list;
private ListDictionary List {
    get {
        if (this.list == null)
            this.list = new ListDictionary(this.caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
        return this.list;
    }
}
private Hashtable hashtable;
private const int FixedSizeCutoverPoint = 6;  // 初始化判定
private const int CutoverPoint = 9;  // 运行时判定(ListDictionary -> Hashtable)
private const int InitialHashtableSize = 13;

初步化HybridDictionary:(假诺开首initialSize >=
6,直接初步化Hashtable)

爱博体育app手机版 25

HybridDictionary运行中,ListDictionary到Hashtable的转变:

爱博体育app手机版 26

HybridDictionary扩大容积:内置Hashtable变量,必然存在二回扩大容积难点,具体见Hashtable。

C# – HybridDictionary类代码 

public class HybridDictionary : IDictionary, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsReadOnly { get; }
    public bool IsSynchronized { get; }
    public object SyncRoot { get; }
    public ICollection Keys { get; }    
    public ICollection Values { get; }
    public object this[object key] { get; set; }   // 键值访问器
    public IDictionaryEnumerator GetEnumerator();  // 枚举器

    public HybridDictionary([int initSize, bool caseInsensitive]);
    public void Add(object key, object value);
    public void Remove(object key);
    public void Clear();
    public bool Contains(object key);
    public void CopyTo(Array array, int index);
}

style=”color: #ff6600; font-size: 16px;”>OrderedDictionary:表示支持键或索引访谈的键/值对的汇合  

真相是哈希表 +
数组实现,支持键值访谈和目录访问

规律完结

OrderedDictionary内部维护贰个ArrayList和贰个Hashtable,增加和删除改查均保持ArrayList和Hashtable的一路。

private ArrayList _objectsArray;
private ArrayList objectsArray {
    get {
        if (this._objectsArray == null)
            this._objectsArray = new ArrayList(this._initialCapacity);
        return this._objectsArray;
    }
}
private Hashtable _objectsTable;
private Hashtable objectsTable {
    get {
        if (this._objectsTable == null)
            this._objectsTable = new Hashtable(this._initialCapacity, this._comparer);
        return this._objectsTable;
    }
}
private int _initialCapacity;

初始化OrderedDictionary:

爱博体育app手机版 27

OrderedDictionary扩容:参见ArrayList和Hashtable。

C# – OrderedDictionary类代码

public class OrderedDictionary : IOrderedDictionary, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback {
    public int Count { get; }
    public bool IsReadOnly { get; }
    public ICollection Keys { get; }
    public ICollection Values { get; }
    public object this[int index] { get; set; }  // 索引访问器
    public object this[object key] { get; set; } // 键值访问器
    public virtual IDictionaryEnumerator GetEnumerator();  // 枚举器

    public OrderedDictionary([int capacity, IEqualityComparer cmp]);
    public OrderedDictionary AsReadOnly();
    public void Add(object key, object value);
    public void Insert(int index, object key, object value);
    public void Remove(object key);
    public void RemoveAt(int index);
    public void Clear();
    public bool Contains(object key);
    public void CopyTo(Array array, int index);
}

style=”color: #ff6600; font-size: 16px;”>StringDictionary:将键和值强类型化为字符串并非指标来贯彻哈希表  

实为是哈希表达成、帮衬键值访谈

规律完毕

StringDictionary内部维护二个Hashtable,匡助Hashtable的暗许开始化:

internal Hashtable contents = new Hashtable();

初始化StringDictionary和StringDictionary扩容:参见Hashtable。

C# – StringDictionary类代码

public class StringDictionary : IEnumerable {
    public virtual int Count { get; }
    public virtual bool IsSynchronized { get; }
    public virtual object SyncRoot { get; }
    public virtual ICollection Keys { get; }
    public virtual ICollection Values { get; }
    public virtual string this[string key] { get; set; }  // 键值访问器
    public virtual IEnumerator GetEnumerator();  // 枚举器

    public StringDictionary();
    public virtual void Add(string key, string value);
    public virtual void Remove(string key);
    public virtual void Clear();
    public virtual bool ContainsKey(string key);
    public virtual bool ContainsValue(string value);
    public virtual void CopyTo(Array array, int index);
}  

字典集小结

爱博体育app手机版 28

从时间复杂度看,查找耗费时间:

  • Hashtable、Dictionary<T, V>、OrderedDictionary:O(1)
  • SortList、SortList<T, V>、SortedDictionary<T,
    V>:O(logN)
  • ListDictinary:O(N)

参考:C#集合–Dictionary

System.Collections.Specialized其余一些

style=”color: #ff6600; font-size: 15px;”>StringCollection:表示字符串的强类型化会集 

实为是ArrayList、帮衬索引访谈

原理达成

StringCollection内部维护一个ArrayList:

private ArrayList data = new ArrayList();

初始化StringCollection和StringCollection扩容:参见ArrayList。

C# – StringCollection类代码

public class StringCollection : IList, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsReadOnly { get; }
    public bool IsSynchronized { get; }
    public object SyncRoot { get; }
    public string this[int index] { get; set; }  // 索引访问器
    public StringEnumerator GetEnumerator();  // 枚举器

    public StringCollection();
    public int Add(string value);
    public void AddRange(string[] value);
    public void Insert(int index, string value);
    public void Remove(string value);
    public void RemoveAt(int index);
    public void Clear();
    public bool Contains(string value);
    public int IndexOf(string value);
    public void CopyTo(string[] array, int index);
}

里头,StringEnumerator协助在StringCollection上进展简要迭代

public class StringEnumerator {
    public string Current { get; }
    public bool MoveNext();
    public void Reset();
}  

style=”color: #ff6600; font-size: 15px;”>NameValueCollection:表示可通过键或索引访问的键(String)和值(String)的成团

本质是哈希表,叁个键、四个值,辅助索引访谈和键值访谈

规律达成

NameValueCollection通过父类NameObjectCollectionBase内部维护的二个ArrayList和叁个Hashtable达成字典集作用:

// System.Collections.Specialized.NameObjectCollectionBase
private ArrayList _entriesArray;  // 保存所有的键值对(NameObjectEntry类型)
private volatile Hashtable _entriesTable;  // Hashtable的常规运用

其中,NameObjectEntry概念结点:

internal class NameObjectEntry{
    internal string Key;
    internal object Value;
    internal NameObjectEntry(string name, object value){
        this.Key = name;  this.Value = value;
    }
}  

NameValueCollection扩容:参见ArrayList和Hashtable。  

C# – NameValueCollection类代码

public class NameValueCollection : NameObjectCollectionBase {
    public virtual string[] AllKeys { get; }
    public string this[int index] { get; }  // 索引访问器
    public string this[string name] { get; set; }  // 键值访问器

    public void Add(NameValueCollection c);
    public virtual void Add(string name, string value);
    public virtual void Remove(string name);
    public virtual void Clear();
    public bool HasKeys();
    public virtual string Get(int index);
    public virtual string Get(string name);
    public virtual void Set(string name, string value);
    public virtual string GetKey(int index);
    public virtual string[] GetValues(int index);
    public virtual string[] GetValues(string name);
    public void CopyTo(Array dest, int index);
}

style=”color: #ff6600; font-size: 15px;”>KeyedCollection<TKey,
TItem>
:提供集结的键嵌入在值中的集结的空洞基类  

支撑键值(项)访谈。内部维护一个Dictionary<TK,
TI>字典集:

private Dictionary<TKey, TItem> dict;

 


上边部分是集结类的其他部分

爱博体育app手机版 29

链表:LinkedList

style=”color: #ff6600;”>LinkedList:表示双向链表

实为是链表完毕、辅助键值访谈。插入特别灵活:八种职位,三种方式,帮助“在此之前以后”和“从后往前”双向查找。

规律达成

LinkedList内部维护三个双向链表:

internal LinkedListNode<T> head;  // 双向链表头结点

链表达成,不设有二次扩大容积的难题。  

C# – LinkedList类代码

public class LinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback {
    public int Count { get; }
    public LinkedListNode<T> First/Last { get; }  // 首尾结点
    public LinkedList<T>.Enumerator GetEnumerator(); // 枚举器

    public LinkedList();
    public LinkedList(IEnumerable<T> collection);
    public void AddAfter/Before(LinkedListNode<T> node, LinkedListNode<T> newNode);
    public LinkedListNode<T> AddAfter/Before(LinkedListNode<T> node, T value);
    public void AddFirst/Last(LinkedListNode<T> node);
    public LinkedListNode<T> AddFirst/Last(T value);
    public void Remove(LinkedListNode<T> node);
    public bool Remove(T value);
    public void RemoveFirst/Last();
    public void Clear();
    public bool Contains(T value);
    public void CopyTo(T[] array, int index);
    public LinkedListNode<T> Find(T value);
    public LinkedListNode<T> FindLast(T value);
}

其中,LinkedListNode代表结点:

public sealed class LinkedListNode<T> {
    public LinkedListNode(T value);
    public LinkedListNode<T> Next { get; }
    public LinkedListNode<T> Previous { get; }
    public T Value { get; set; }   // 结点包含的值
    public LinkedList<T> List { get; }  // 结点所属的链表
}    

参考:.net集结类的切磋–链表—ListDictionary,LinkedList<T>

栈:Stack – Stack<T>

style=”color: #ff6600; font-size: 16px;”>Stack:对象的后进先出(LIFO)非泛型集结

规律实现

Stack内部维护二个数组:

private object[] _array;
private const int _defaultCapacity = 10;

初始化Stack:

爱博体育app手机版 30

Stack扩大体积:存在二倍扩大容积难点。

C# – Stack类代码

public class Stack : ICollection, IEnumerable, ICloneable {
    public virtual int Count { get; }
    public virtual bool IsSynchronized { get; }
    public virtual object SyncRoot { get; }

    public Stack();
    public Stack(int initCapacity);
    public Stack(ICollection col);
    public virtual object Clone();  // 浅表副本
    public static Stack Synchronized(Stack stack);
    public virtual IEnumerator GetEnumerator();  // 枚举器
    public virtual object Peek();
    public virtual void Push(object obj);
    public virtual object Pop();   
    public virtual void Clear();
    public virtual bool Contains(object obj);
    public virtual object[] ToArray();
    public virtual void CopyTo(Array array, int index);
}

Stack class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:大小可变的后进先出
(LIFO)
泛型集结,存款和储蓄同一等级次序的即兴实例  

规律达成

Stack<T>内部维护三个数组:

private T[] _array;
private static T[] _emptyArray = new T[0];
private const int _defaultCapacity = 4;

初始化Stack<T>:

爱博体育app手机版 31

Stack<T>扩容(入栈):

爱博体育app手机版 32  

C# – Stack<T>类代码

public class Stack<T> : IEnumerable<T>, ICollection, IEnumerable {
    public int Count { get; }

    public Stack();
    public Stack(int capacity);
    public Stack(IEnumerable<T> collection);
    public T Peek();
    public void Push(T item);
    public T Pop();
    public void Clear();
    public bool Contains(T item);
    public T[] ToArray();
    public void CopyTo(T[] array, int arrayIndex);

    public Stack<T>.Enumerator GetEnumerator();  // 枚举器
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator {}
}

队列:Queue – Queue<T>

style=”font-size: 16px; color: #ff6600;”>Queue:对象的先进先出(FIFO)非泛型群集

原理实现

Queue内部维护一个数组:

private object[] _array;
private int _growFactor;  // 增长因子
private const int _MinimumGrow = 4;
private const int _ShrinkThreshold = 32;
public Queue() : this(32, 2f) {}

初始化Queue:

爱博体育app手机版 33

Queue扩大体量:存在二倍扩大体量难题。

C# – Queue类代码

public class Queue : ICollection, IEnumerable, ICloneable {
    public virtual int Count { get; }
    public virtual bool IsSynchronized { get; }
    public virtual object SyncRoot { get; }

    public Queue();
    public Queue(int capacity);
    public Queue(ICollection col);
    public virtual object Clone();
    public static Queue Synchronized(Queue queue);
    public virtual IEnumerator GetEnumerator();
    public virtual object Peek();
    public virtual void Enqueue(object obj);
    public virtual object Dequeue();
    public virtual void Clear();
    public virtual bool Contains(object obj);
    public virtual void CopyTo(Array array, int index);
    public virtual object[] ToArray();
}

Queue class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:对象的先进先出(FIFO)泛型集结

原理实现

Queue<T>内部维护二个数组:

private T[] _array;
private const int _GrowFactor = 200;
private const int _MinimumGrow = 4;
private const int _ShrinkThreshold = 32;  // 未用到
private static T[] _emptyArray = new T[0];  // 用于初始化数组
private const int _DefaultCapacity = 4;

初始化Queue<T>:

爱博体育app手机版 34

Queue<T>扩容(入队):

爱博体育app手机版 35

C# – Queue类代码

public class Queue<T> : IEnumerable<T>, ICollection, IEnumerable {
    public int Count { get; }

    public Queue();
    public Queue(int capacity);
    public Queue(IEnumerable<T> collection);
    public T Peek();
    public void Enqueue(T item);
    public T Dequeue();
    public void Clear();
    public bool Contains(T item);
    public void CopyTo(T[] array, int arrayIndex);
    public T[] ToArray();

    public Queue<T>.Enumerator GetEnumerator();  // 枚举器
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator {}
}

Set集合:HashSet<T> – SortedSet<T>

ISet class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:提供用于集结的抽象化的基接口 

public interface ISet<T> : ICollection<T>, IEnumerable<T>, IEnumerable {
    bool Add(T item);
    bool Overlaps(IEnumerable<T> other);  // 重叠(是否有交集)
    bool SetEquals(IEnumerable<T> other); // 相等
    // 修改当前集合
    void UnionWith(IEnumerable<T> other);     // 并集
    void IntersectWith(IEnumerable<T> other); // 交集
    void ExceptWith(IEnumerable<T> other);    // 差集
        void SymmetricExceptWith(IEnumerable<T> other);  // 并集 - 交集   
}  

HashSet<T>和SortedSet<T>均落实ISet<T>接口,用于独一项、不允许再一次成分(若增多重复成分,Add()方法重回false,而Hashtable/Dictionary<TK,电视机>会一向抛出拾叁分),扶助交集、并集、差集等运算,但Set集结不支持键值访问、也不协助索引访谈。

HashSet class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:表示值的集结  

本质是哈希表,但不协理键值访谈、也不帮衬索引访谈

参考:.net群集类的切磋–哈希表(二)–HashSet<T>

.NET 3.5 新扩展,“哈希群集”,与Dictionary<TK,电视>采纳一样的囤积方式和哈希争持算法,查找速度快O(1)。

原理完毕

HashSet<T>内部维护七个数组:三个正规数组m_buckets和三个Slot类型的数组变量,Slot是一个社团,用来保存Value、哈希值和指针:

private int[] m_buckets;
private HashSet<T>.Slot[] m_slots;

中间,Slot结构类型定义

internal struct Slot{
    internal int hashCode;
    internal T value;
    internal int next;
}

初始化HashSet<T>:  

爱博体育app手机版 36

HashSet<T>扩大体积:具体难点参见Dictionary<TK, 电视>。

C# – HashSet<T>类代码

public class HashSet<T> : ISerializable, IDeserializationCallback, ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable {
    public int Count { get; }
    public IEqualityComparer<T> Comparer { get; }  // 相等比较器

    // 未指定相等比较器IEqualityComparer<T>的HashSet<T>,使用集合类型默认的相等比较器
    public HashSet();
    public HashSet(IEnumerable<T> collection);
    public HashSet(IEqualityComparer<T> comparer);
    public bool Add(T item);
    public bool Remove(T item);
    public int RemoveWhere(Predicate<T> match);  // 支持函数式编程,Lambda表达式
    public void Clear();
    public bool Contains(T item);    
    public void CopyTo(T[] array [, int arrayIdx, int cnt]);

    public bool Overlaps(IEnumerable<T> other);
    public bool SetEquals(IEnumerable<T> other);
    public void IntersectWith(IEnumerable<T> other);
    public void UnionWith(IEnumerable<T> other);
    public void ExceptWith(IEnumerable<T> other);

    public HashSet<T>.Enumerator GetEnumerator();  // 枚举器
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator {}
}

style=”color: #ff6600; font-size: 16px;”>SortedSet class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:表示值的不改变聚焦  

实为是红黑树完成,不协理键值访问、也不援助索引访谈

.NET 4.0 新增,有序的Set集合。

规律达成

SortedSet<T>内部维护一棵红黑树:

private SortedSet<T>.Node root;

当中,红黑树结点定义  

internal class Node{
    public bool IsRed;
    public T Item;
    public SortedSet<T>.Node Left;
    public SortedSet<T>.Node Right;
    public Node(T item){
        this.Item = item;  this.IsRed = true;
    }       
    public Node(T item, bool isRed){
        this.Item = item;  this.IsRed = isRed;
    }
}  

C# – SortSet<T>类代码

public class SortedSet<T> : ISet<T>, ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback {
    public int Count { get; }
    public T Max { get; }
    public T Min { get; }
    public IComparer<T> Comparer { get; }  // 比较器

    public SortedSet();
    public SortedSet(IEnumerable<T> collection);
    public SortedSet(IComparer<T> comparer);
    public bool Add(T item);
    public bool Remove(T item);
    public int RemoveWhere(Predicate<T> match);  // 函数式编程
    public virtual void Clear();
    public virtual bool Contains(T item);
    public void CopyTo(T[] array [, int idx, int cnt]);

    public bool Overlaps(IEnumerable<T> other);
    public bool SetEquals(IEnumerable<T> other);
    public virtual void IntersectWith(IEnumerable<T> other);
    public void UnionWith(IEnumerable<T> other);
    public void ExceptWith(IEnumerable<T> other);
    public virtual SortedSet<T> GetViewBetween(T lowerValue, T upperValue);  // 子集合的视图

    public IEnumerable<T> Reverse();  // 返回一个逆序访问SortedSet<T>的枚举器
    public SortedSet<T>.Enumerator GetEnumerator();  // 枚举器
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator, ISerializable, IDeserializationCallback {}
}

线程安全集合:ConcurrentXxx

.NET-4.0从前,线程安全性通过Synchronized()方法达成,对各样加多或移除操作锁定任何集合,导致各类尝试访谈群集的线程必须一直等候,直到轮到它来拿到锁,不能伸缩、质量低。

.NET-4.0提供新的线程安全和扩展的产出群集,能消除潜在的死锁难点和竞争原则难题,使集结尽或者减少须求使用锁的次数、优化为最好质量,幸免生出不要求的贰只花费。命名空间System.Collections.Concurrent富含多个线程安全、可伸缩的集结类,5种新的成团类型专项使用于为三十二线程安全急忙地加上和移除操作提供扶助,在那之中,ConcurrentStack<T>和ConcurrentQueue<T>是全然无锁的,通过System.Threading.Interlocked操作达成线程安全性。

  • Allows for multiple readers in a lock, and then once a writer grabs
    the lock it blocks all further readers until the writer is done.

爱博体育app手机版 37

参考

style=”color: #ff6600; font-size: 16px;”>IProducerConsumerCollection class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:定义供创造者/费用者用来操作线程安全的集纳的格局

落到实处该接口能够落成全体”生产者-花费者”行为的类。

public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection, IEnumerable {
    void CopyTo(T[] array, int index);
    T[] ToArray();
    bool TryAdd(T item);
    bool TryTake(out T item);
}

style=”color: #ff6600; font-size: 16px;”>ConcurrentStack class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:线程安全的后进先出
(LIFO) 集结

实为是单链表完成

爱博体育app手机版 38

原理完结

ConcurrentStack<T>内部维护三个单链表: 

private volatile ConcurrentStack<T>.Node m_head;
private const int BACKOFF_MAX_YIELDS = 8;

个中结点定义:

private class Node {
    internal readonly T m_value;
    internal ConcurrentStack<T>.Node m_next;
    internal Node(T value) {
        this.m_value = value; this.m_next = null;
    }
}  

Count 与 IsEmpty

爱博体育app手机版 39

C# –
ConcurrentStack<T>类代码

public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsEmpty { get; }
    public IEnumerator<T> GetEnumerator();  // 枚举器

    public ConcurrentStack();
    public ConcurrentStack(IEnumerable<T> collection);
    public void Push(T item);
    public void PushRange(T[] items [, int startIdx, int cnt]);
    public bool TryPeek(out T result);
    public bool TryPop(out T result);
    public int TryPopRange(T[] items [, int startIdx, int cnt]);
    public void Clear();
    public void CopyTo(T[] array, int index);
    public T[] ToArray();
}

参考:.Net中的并行编制程序-2.ConcurrentStack的完毕与深入分析; 

style=”color: #ff6600; font-size: 16px;”>ConcurrentQueue class=”token tag”> class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:线程安全的先进先出
(FIFO) 集结

精神是数组+链表

爱博体育app手机版 40

原理完毕

ConcurrentQueue<T>采用分段存款和储蓄的艺术,内部存款和储蓄器分配以段(Segment)为单位,三个段中间含有一个暗中认可长度为32的数组和针对下八个段的指针,内部结构暗暗提示图:

爱博体育app手机版 41

ConcurrentQueue<T>内部维护四个Head和Tail指针分别指向初阶段和得了段,操作ConcurrentQueue实质是对Segment(数据段)的操作:

private volatile ConcurrentQueue<T>.Segment m_head;  // 起始段
private volatile ConcurrentQueue<T>.Segment m_tail;  // 结束段
private const int SEGMENT_SIZE = 32; // 段大小

其中,数据段Segment定义:

private class Segment {
    internal volatile T[] m_array;  // 存储实际数据
    internal volatile VolatileBool[] m_state;  // 指示该位置是否可用
    private volatile ConcurrentQueue<T>.Segment m_next;  // 段指针
    internal readonly long m_index;  //当前段在(数据段)链表中的位置
    private volatile int m_low;  // m_array的头指针
    private volatile int m_high; // m_array的尾指针
    private volatile ConcurrentQueue<T> m_source;  // 数据段链表(整个队列)

    internal Segment(long index, ConcurrentQueue<T> source){
        this.m_array = new T[32];
        this.m_state = new VolatileBool[32];
        this.m_high = -1;
        this.m_index = index;
        this.m_source = source;
    }
} 

爱博体育app手机版 42爱博体育app手机版 43

  1     internal ConcurrentQueue.Segment Next{
  2         get{ return this.m_next; }
  3     }
  4     internal bool IsEmpty{
  5         get{ return this.Low > this.High; }
  6     }
  7     internal int Low{
  8         get{ return Math.Min(this.m_low, 32); }
  9     }
 10     internal int High{
 11         get{ return Math.Min(this.m_high, 31); }
 12     }
 13 
 14     internal void UnsafeAdd(T value){
 15         this.m_high++;
 16         this.m_array[this.m_high] = value;
 17         this.m_state[this.m_high].m_value = true;
 18     }
 19 
 20     internal ConcurrentQueue.Segment UnsafeGrow(){
 21         ConcurrentQueue.Segment segment = new ConcurrentQueue.Segment(this.m_index + 1L, this.m_source);
 22         this.m_next = segment;
 23         return segment;
 24     }
 25     internal void Grow(){
 26         ConcurrentQueue.Segment next = new ConcurrentQueue.Segment(this.m_index + 1L, this.m_source);
 27         this.m_next = next;
 28         this.m_source.m_tail = this.m_next;
 29     }
 30     internal bool TryAppend(T value){
 31         if (this.m_high >= 31){
 32             return false;
 33         }
 34         int num = 32;
 35         try{
 36         }
 37         finally{
 38             num = Interlocked.Increment(ref this.m_high);
 39             if (num <= 31){
 40                 this.m_array[num] = value;
 41                 this.m_state[num].m_value = true;
 42             }
 43             if (num == 31){
 44                 this.Grow();
 45             }
 46         }
 47         return num <= 31;
 48     }
 49     internal bool TryRemove(out T result){
 50         SpinWait spinWait = default(SpinWait);
 51         int i = this.Low;
 52         int high = this.High;
 53         while (i <= high)
 54         {
 55             if (Interlocked.CompareExchange(ref this.m_low, i + 1, i) == i){
 56                 SpinWait spinWait2 = default(SpinWait);
 57                 while (!this.m_state[i].m_value){
 58                     spinWait2.SpinOnce();
 59                 }
 60                 result = this.m_array[i];
 61                 if (this.m_source.m_numSnapshotTakers <= 0){
 62                     this.m_array[i] = default(T);
 63                 }
 64                 if (i + 1 >= 32){
 65                     spinWait2 = default(SpinWait);
 66                     while (this.m_next == null){
 67                         spinWait2.SpinOnce();
 68                     }
 69                     this.m_source.m_head = this.m_next;
 70                 }
 71                 return true;
 72             }
 73             spinWait.SpinOnce();
 74             i = this.Low;
 75             high = this.High;
 76         }
 77         result = default(T);
 78         return false;
 79     }
 80     internal bool TryPeek(out T result){
 81         result = default(T);
 82         int low = this.Low;
 83         if (low > this.High){
 84             return false;
 85         }
 86         SpinWait spinWait = default(SpinWait);
 87         while (!this.m_state[low].m_value){
 88             spinWait.SpinOnce();
 89         }
 90         result = this.m_array[low];
 91         return true;
 92     }
 93     internal void AddToList(List list, int start, int end)
 94         for (int i = start; i <= end; i++)
 95         {
 96             SpinWait spinWait = default(SpinWait);
 97             while (!this.m_state[i].m_value){
 98                 spinWait.SpinOnce();
 99             }
100             list.Add(this.m_array[i]);
101         }
102     }
103 
104 ConcurrentQueue<T>.Segment

ConcurrentQueue<T>.Segment

初始化ConcurrentQueue<T>:

爱博体育app手机版 44

Count 与 IsEmpty

爱博体育app手机版 45

C#
– ConcurrentQueue<T>类代码

public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsEmpty { get; }
    public IEnumerator<T> GetEnumerator();  // 枚举器

    public ConcurrentQueue();
    public ConcurrentQueue(IEnumerable<T> collection);
    public void Enqueue(T item);
    public bool TryDequeue(out T result);
    public bool TryPeek(out T result);
    public void CopyTo(T[] array, int index);
    public T[] ToArray();
}

参考:.Net中的并行编制程序-3.ConcurrentQueue完毕与解析; 

style=”color: #ff6600;”>ConcurrentDictionary<TK,
TV>
:允许四个线程同不日常候做客的线程安全的键值对群集 

真相是哈希表(数组+链表)、协理键值访谈

爱博体育app手机版 46

原理达成

ConcurrentDictionary<TK,
TV>的中间类Tables维护一个数组变量m_buckets存款和储蓄实际多少(内部存款和储蓄结构类似邻接表):

private volatile ConcurrentDictionary<TKey, TValue>.Tables m_tables;
private const int DEFAULT_CAPACITY = 31;
private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4;
private class Tables{
    internal readonly ConcurrentDictionary<TK, TV>.Node[] m_buckets;  
    internal readonly object[] m_locks;
    internal volatile int[] m_countPerLock;
    internal readonly IEqualityComparer<TK> m_comparer;  // 比较器
    internal Tables(ConcurrentDictionary<TK, TV>.Node[] buckets, object[] locks, int[] countPerLock, IEqualityComparer<TK> comparer){
        this.m_buckets = buckets;
        this.m_locks = locks;
        this.m_countPerLock = countPerLock;
        this.m_comparer = comparer;
    }
} 

个中,字典集成分Node定义:

private class Node {
    internal TKey m_key;
    internal TValue m_value;
    internal volatile ConcurrentDictionary<TKey, TValue>.Node m_next;
    internal int m_hashcode;
    internal Node(TKey key, TValue value, int hashcode, ConcurrentDictionary<TKey, TValue>.Node next){
        this.m_key = key;
        this.m_value = value;
        this.m_next = next;
        this.m_hashcode = hashcode;
    }
}

初始化ConcurrentDictionary<TK, TV>:

爱博体育app手机版 47

爱博体育app手机版 48

插入操作:ConcurrentDictionary<TK,
电视>的TryAdd()方法会调用TryAddInternal()方法添比索素,具体:

爱博体育app手机版 49

中间,num是因素在桶内的任务(GetBucketAndLockNo()方法的bucketNo参数),node是有些链表的尾结点:

爱博体育app手机版 50

ConcurrentDictionary<TK,
TV>扩大体量:通过GrowTable()方法实现,类似Dictionary<TK,
电视>,但是并不曾鲜明重新总括hashcode。

爱博体育app手机版 51

遍历字典集

GetEnumerator() or iterate using a foreach会产生数据脏读(Dirty
Read),推荐遍历方法:

foreach (  var item in myConcurrentDic.ToArray()  ){
    Console.WriteLine(item.Key + ": " + item.Value);
}

C# – ConcurrentDictionary<TK,
TV>类代码

public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsEmpty { get; }
    public ICollection<TK> Keys { get; }
    public ICollection<TV> Values { get; }
    public TValue this[TKey key] { get; set; }  // 键值访问器
    public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator();  // 枚举器

    public ConcurrentDictionary();
    public ConcurrentDictionary(IEnumerable<KeyValuePair<TK, TV>> collection, IEqualityComparer<TK> cmp);
    public ConcurrentDictionary(int concurrencyLevel, int capacity); // 并发级别(估计的线程数量)
    public bool TryAdd(TKey key, TValue value);   
    public bool TryRemove(TKey key, out TValue value);
    public void Clear();
    public bool ContainsKey(TKey key);
    public bool TryGetValue(TKey key, out TValue value);
    public KeyValuePair<TKey, TValue>[] ToArray();

    public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue);
    public TValue GetOrAdd(TKey key, TValue value);
    public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory);
    public TValue AddOrUpdate(TK key, TV addValue, Func<TK, TV, TV> updateValueFactory);
    public TValue AddOrUpdate(TK key, Func<TK, TV> addValueFactory, Func<TK, TV, TV> updateValueFactory);
}

参考:.net源码解析 –
ConcurrentDictionary<TKey,
电视alue>

style=”background-color: initial;”>ConcurrentBag class=”token tag” style=”background-color: initial;”> class=”token tag”> style=”color: #ff6600; font-size: 16px;”><T class=”token punctuation”> style=”color: #ff6600; font-size: 16px;”>>:对象的线程安全的无序集中 style=”background-color: initial;”>  

本质是双向链表

爱博体育app手机版 52

要素可重复的冬天集聚,允许为空null:This makes the bag handy for those
cases when all you care about is that the data be consumed eventually,
without regard for order of consumption or even fairness.

  • 在纯生产者-花费者中,ConcurrentBag<T>试行进程或许会比其余并发集结类型的推行进程慢得多;

  • 在混合生产者-花费者中,无论是微量行事负荷依然大大方方行事负荷情况下,ConcurrentBag<T>实施进程会比任何其余并发群集类型越来越快、可伸缩性越来越好;

爱博体育app手机版 53

  • Take advantage of the new ThreadLocal<T> type, so that
    each thread using the bag has a list local to just that thread. 
  • The work-stealing synchronization would outweigh the thread-local
    optimization for a thread taking its own items.

原理完毕

ConcurrentBag<T>的里边类ThreadLocalList定义三个双向链表(每贰个双向链表对应归属二个线程):

internal class ThreadLocalList {
    internal Thread m_ownerThread; //当前链表所属的线程
    internal volatile ConcurrentBag<T>.Node m_head; // 表头
    private volatile ConcurrentBag<T>.Node m_tail;  // 表尾
    private int m_count;  // 当前链表元素数
    internal volatile int m_currentOp;  // 当前链表在链表池中的位置
    internal volatile ConcurrentBag<T>.ThreadLocalList m_nextList;  // 指向下一个链表   
    internal int m_stealCount;
    internal bool m_lockTaken;  
} 

ConcurrentBag<T>内部维护二个双向链表池:

private ThreadLocal<ConcurrentBag<T>.ThreadLocalList> m_locals;
private volatile ConcurrentBag<T>.ThreadLocalList m_headList;  // 首链表
private volatile ConcurrentBag<T>.ThreadLocalList m_tailList;  // 尾链表

中间,链表节点Node定义:

internal class Node{
    public readonly T m_value;
    public ConcurrentBag<T>.Node m_next;
    public ConcurrentBag<T>.Node m_prev;
    public Node(T value){
        this.m_value = value;
    }
}

结构函数会调用Initialize()方法开首化ConcurrentBag<T>:

爱博体育app手机版 54 

C#
– ConcurrentBag<T>类代码

public class ConcurrentBag<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable {
    public int Count { get; }
    public bool IsEmpty { get; }
    public IEnumerator<T> GetEnumerator();  // 枚举器

    public ConcurrentBag();
    public ConcurrentBag(IEnumerable<T> collection);
    public void Add(T item);
    public bool TryPeek(out T result);
    public bool TryTake(out T result);
    public void CopyTo(T[] array, int index);
    public T[] ToArray();
}    

参考:.NET 4.0 and
System.Collections.Concurrent.ConcurrentBag

style=”color: #ff6600; font-size: 16px;”>BlockingCollection<T>:为贯彻了IProducerConsumerCollection class=”token tag”> class=”token punctuation”><T class=”token punctuation”>>接口的线程安全群集提供阻止和限制功能

参考:BlockingCollection
概述
.aspx);

对IProducerConsumerCollection<T>接口的兑现,适合创设达成基于”生产者-费用者”的应用程序,约等于将一个非阻塞集结转换成叁个梗阻集合,与杰出的围堵队列数据结构类似,适用于多少个义务对集中增多、删除数据。

爱博体育app手机版 55

其他: 

  • 支持可选的最大体积,封装完成IProducerConsumerCollection<T>接口的别的聚众类型;
  • 在群集为空或已满时发出堵塞的插入和移除操作;
  • 计时阻塞操作:不会发生堵塞或只在钦点的时刻段内爆发短路的“尝试”插入和移除操作;
  • 支撑foreach的两类枚举:[1].
    只读枚举(静态,a snapshot of the Collection at the time of the
    call);[2]. 在枚举项时将项移除的枚举(动态,等待-执行-等待-实行…);

:暗许集结类型ConcurrentQueue<T>,Because it is fairly
light and maximizes fairness by ordering items so that they are consumed
in the same order they are produced.

在急需限制和鸿沟语义时,BlockingCollection<T>实践进程恐怕会比别的自定义完成的实践进程都快。

爱博体育app手机版 56

原理完结

  • 添加:四个线程或任务可同时向聚集中添加Add项,若集合到达上限体积,则生成线程阻塞、直到集合中的有些项被移除(if
    a producer creates an item, but there is no space to store it, it
    must wait until an item is consumed);
  • 移除:两个买主可同期移除Take项,若集结变为空,则花费线程发生堵塞、直到生产者添加某些项(if
    a consumer goes to consume an item and none exists, it must wait
    until an item is produced); 

方法CompleteAdding()和属性IsCompleted

当使用CompleteAdding()方法后且集合内未有成分时,属性IsCompleted此时会为True,(在劳动者-花费者难题中)可用于判定当前集中内的保有因素是不是都被处理完。

爱博体育app手机版 57

C# –
BlockingCollection<T>类代码

public class BlockingCollection<T> : IEnumerable<T>, ICollection, IEnumerable, IDisposable {
    public int BoundedCapacity { get; }  // 默认值int.MaxValue
    public int Count { get; }
    public bool IsAddingCompleted { get; }  // 集合是否已被标记为已完成添加
    public bool IsCompleted { get; }  // 集合是否已被标记为已完成添加并且集合当前为空
    // 枚举器:从集合中返回并移除某一项
    public IEnumerable<T> GetConsumingEnumerable([CancellationToken cancellationToken]);

    // 构造函数(+4 重载)
    // collection:用作基础数据存储区的集合,boundedCapacity:上限容量
    public BlockingCollection([IProducerConsumerCollection<T> collection, int boundedCapacity]);
    public void Add(T item [, CancellationToken cancellationToken]);
    public T Take([CancellationToken cancellationToken]);
    public bool TryAdd(T item [, int millisecondsTimeout, CancellationToken cancellationToken]);
    public bool TryTake(out T item [, int millisecondsTimeout, CancellationToken cancellationToken]);
    public static int AddToAny(BlockingCollection<T>[] collections, T item [, CancellationToken cancellationToken]);
    public static int TakeFromAny(BlockingCollection<T>[] collections, out T item [, CancellationToken cancellationToken]);
    public static int TryAddToAny(BlockingCollection<T>[] collections, T item [, int millisecondsTimeout, CancellationToken cancellationToken]);
    public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item [, int millisecondsTimeout, CancellationToken cancellationToken]);
    public void CompleteAdding();   // 将BlockingCollection<T>实例标记为不再接受任何添加
    public void Dispose();   // 释放BlockingCollection<T>实例占用的资源
    protected virtual void Dispose(bool disposing);
    public void CopyTo(T[] array, int index);
    public T[] ToArray();
}

其中,CancellationToken代表传播关于应注销操作的打招呼

public struct CancellationToken {
    public bool CanBeCanceled { get; }  // 标记是否能处于已取消状态
    public bool IsCancellationRequested { get; }  // 是否已请求取消此标记
    public static CancellationToken None { get; } // 返回空CancellationToken值
    public WaitHandle WaitHandle { get; }  // 获取在取消标记时处于有信号状态的System.Threading.WaitHandle

    public CancellationToken(bool canceled);
}   

参考:

 


上面部分是多少个易混淆知识点总结:

至于数组

  • Array:数组基类,针对任性等级次序(可以初步化为随机档期的顺序、但最早化后项目定位)、固定长度
  • []:常规数组,针对一定项目、固定长度
  • ArrayList:动态数组,针对猖狂等级次序、率性长度
  • List<T>:泛型线性表,针对一定项目、放肆长度

List<T> 与
Dictionary<K, V> 

  • List<T>内部存款和储蓄器中一连存储、遍历效能高,Dictionary<K,
    V>/HashTable由均Hash算法发生内部存款和储蓄器地址、遍历效用低、且存款和储蓄空间费用代价大;
  • List<T>查找成分通过Exists()方法循环查找、成效低,Dictionary<K,
    V>通过Hash查找、功效高;

参考:Dictionary<T1,T2>和List<T>作用难题

Dictionary<K, V>
与 Hashtable
  

  • Dictionary<K,
    V>类型约束新澳元素,HashTable可增添任性等级次序的成分;
  • Dictionary<K,V>无须装箱、拆箱操作,HashTable增添服装箱、读取时拆箱(耗费时间);
  • Dictionary<K,V>依据插入顺序来遍历、珍视顺序性,HashTable遍历顺序与插入顺序差异等;
  • 单线程程序中援用应用Dictionary<K,V>(泛型优势、类型安全,读取速度快,空间利用丰硕,但非线程安全、需人为lock锁定、功用低),三十二线程程序中推荐应用Hashtable(允许单线程写入、二十四线程读取,Synchronized()方法可获得完全线程安全的项目);
  • 从数据结构角度,两个均需求对键值进行散列操作,区别是拍卖哈希争辩碰撞的不二秘技:Dictionary<K,V>选拔链接法(Chaining),Hashtable选择开放寻址法(Open
    Addressing); 
  • Hashtable扩大体量特别耗费时间,空间攻下大、利用率偏低、受填充因子影响大,扩大体量时怀有的多寡须求再行张开散列计算,Dictionary<K,V>即便也是有扩大容积难题、但没有需求再一次散列;

参考:关于Hashtable与Dictionary品质研究
 闲话Hashtable与Dictionary之哈希寻址方法; 

**SortedList/SortedList<K,
V> 与 SortedDictionary<K, V> **

爱博体育app手机版 58

  • 前端通过2个数组实现(检索O(logN)、插入删除O(N)),后面一个通过红黑树完成(检索插入删除O(logN))、占用存款和储蓄空间大;
  • 前面八个扶助索引、神速搜索质量好,后面一个不帮助索引;
  • 前端是有序线性表,前面一个是平衡二叉树;

HashSet<T> 与
SortedSet<T> 

  • HashSet<T>是冬季不重复的Hash集合,SortedSet<T>是稳步不重复的Set集合(自动排序);
  • HashSet<T>基于哈希的查询、Contains实施特别快捷、O(1)增加和删除改查,SortedSet<T>是O(log(N))的增加和删除改查;

聚拢选取难题浅析

参考:

相关文章