本系列學習在.NET中的併發並行編程模式,實戰技巧程序員
.NET不可變集合.NET併發集合函數式數據結構設計一個不可變類編程
做爲程序員常常遇到產品上線後出現各類莫名其妙的問題,在我本地是好好的啊,也成爲程序員面對未知問題的第一反應。這種不容易復現的問題,無非就是硬件不一致和軟件不一致,更多的問題出在軟件環境上,用戶量、 併發這種測試容易遺漏的點。安全
爲了保證編寫的代碼在不一樣的環境中出現一致的行爲結果,一般就要利用不可變的數據結構。數據一旦建立後就不能修改其自己,修改後會產生新的數據。數據結構
在.NET4.5引入不可變集合,在命名空間System.Collecttions.Immutable中。(注意這個類庫不是.net核心類庫,須要從nuget上安裝)。不可變的集合結構每次修改數據後都會生成新的集合。像String類型同樣,對它Substring,Replace都會生成新的字符串。多線程
//能夠將普通可變集合直接轉爲不可變集合
var dic = new Dictionary<int, int>().ToImmutableDictionary();
//直接建立不可變集合
var list = ImmutableList.Create<int>();
list = list.Add(1);
list = list.Add(2);
list = list.Add(3);
因爲集合不可變,也就保證了多線程的安全。直接將集合丟給每一個線程,原始集合不會變化。併發
還有一種線程安全集合在System.Collections.Concurrent中,在多線程環境中建議使用此類集合。Concurrent集合是可變集合,但提供了細粒度和無鎖模式來提升多線程應用程序的性能和可擴展性。像ConcurrentDictionary字典,除了像傳統字典Dictionary使用,還提供了不少兼容併發的方法,如AddOrUpdate或GetOrAdd等。若是不使用併發集合,在多線程環境中咱們須要設置鎖來保證數據的一致性。app
可持久化數據結構也稱之爲函數式數據結構。可持久化意味着數據結構是不可變的,修改只會返回修改後的新數據結構。(這裏數據持久化和IO持久化區分)。大多數命令式數據結構都是短暫的,修改就破壞其結構。如Dictionary,List,Queue等。編程語言
不可變性可能會帶來必定的損耗,每次修改都會生成新的數據數據結構。但在託管編程語言中,如C# 和Java中,已經作了足夠多的優化,且在多核時代,基本能夠忽略性能的影響。函數
以鏈表數據結構爲例說明託管語言在共享數據結構上作的優化性能
不可變的數據集合,每次修改後,不是完整拷貝原集合,好比集合中追加一項,只會修改引用指向的位置,共享剩餘其餘結構。
C#有readonly和const兩個關鍵字,還記得他們的區別和用處嗎。const靜態常量,編譯時被解析,經過類訪問。readonly動態常量,可延遲到構造函數中初始化,經過類實例訪問。
public class Person
{
public const string Contry = "中國";
public string Name { get; }
public readonly Address Address;
public Person(string name, Address address)
{
this.Name = name;
this.Address = address;
}
}
public class Address
{
public string Street;
public Address(string street)
{
this.Street = street;
}
}
代碼示例中,控制了Person的Address地址是不能被修改的,但它的底層字段Street仍然能夠被修改。這就會致使person.Address.Street="M78星雲"這樣的行爲,因此這就是淺不可變。微軟考慮到不可變編程的重要性,隨後又在C#6.0又引入了自動屬性的概念,能夠輕鬆的建立一個不可變類。像示例中的public string Name { get; }這樣。
to be contiued!
下集:數據並行
寫給普通:
習慣了是個很強大的詞
它能夠代替全部的一言難盡