寫在開頭: html
http://www.cnblogs.com/luminji 157個建議_勘誤表c++
一:屬性算法
屬性和方法同樣。也能夠是virtual和abstract.數據庫
運行時常量優於編譯時常量【能正確運行纔是關鍵】。編譯時常量比運行時常量稍微塊一點,可是缺少靈活性。性能很是關鍵,其值永遠不變的狀況下,咱們才應該使用編譯時常量。編程
c# readonly 運行時常量【構造器一旦執行則不能對值進行修改】 const編譯時常量c#
編譯時常量編譯後會把該常量替換成常量的值,相似於c++的宏【編譯時常量只能夠用於基元類型(整數浮點數枚舉字符串)】。運行時編譯後任然是該變量的引用windows
操做符as和is都只檢查被轉換對象的運行時類型,並不執行其餘的操做。若是被轉換對象的運行時類型既不是所轉換的目標類型,也不是其派生類型,那麼轉型將告失敗跨域
as操做符不能用於值類型,int值類型,不能爲null.數組
as是直接轉安全
只有當咱們不能使用as操做符來進行類型轉換時,才應該使用is操做符。
若是咱們打算使用as來作轉型,那麼再使用is檢查就沒有必要了。直接將as操做符的運算結果和null進行比對就能夠了,這樣比較簡單
c# is和as的區別
is就是處於對類型的判斷。返回true和false。若是一個對象是某個類型或是其父類型的話就返回爲true,不然的話就會返回爲false。另外is操做符永遠不會拋出異常。代碼以下:
若是對象引用爲null,那麼is操做符老是返回爲false,由於沒有對象能夠檢查其類型,就像下面代碼同樣
if(o is Employee)
{
Employee e = (Employee) o;
//在if語句中使用e
}
as :as必須和能夠爲NUll類型使用。轉int則不行
Employee e = o as Employee;
if(e != null)
{
//在if語句中使用e
}
這種as操做即使等同於上面代碼,同時只進行了1次的類型檢查,因此提升了性能。若是類型相同就返回一個非空的引用,不然就返回一個空引用。
條款4:使用Conditional特性代替#if條件編譯
條款5:老是提供ToString()方法
條款6:明辨值類型和引用類型的使用場合
值類型用於存儲數據,引用類型用於定義行爲
條款7:將值類型儘量實現爲具備常量性和原子性的類型
枚舉將None=0聲明出來
ReferenceEquals(): 無論比較的是引用類型仍是值類型,該方法都判斷的是「引用相等」,而非「值相等」,意味着若是咱們使用此來比較兩個值類型,其結果永遠返回false。即便咱們將一個值類型和自身進行比較,ReferenceEquals()的返回值還是false。致使這種結果的緣由在於裝箱
Object.Equals() 默認是引用判斷,可是值類型例外,判斷值類型時須要重寫Equals()方法。若是兩個值類型變量的類型相同,而且內容一致,這兩個變量才被認爲相等。
判斷是否引用的同一個對象時的注意點: string a="aa"; string b = "aa"; 兩個比較都是相等的。這是由於系統並無給字符串b分配內存,只是將"aa"指向了b。因此a和b指向的是同一個字符串(字符串在這種賦值的狀況下作了內存的優化)
相等的數學屬性:自反(任何對象都與其自身相等)、對稱(相等判斷的順序是可有可無的)和可傳遞(a=b b=c 則a=c)
條款10:理解GetHashCode()方法的缺陷
注意; a="aa" b="aa" unity中能夠經過散列碼GetHashCode()間接的查看兩個變量的地址是否相等,可是數組的地址是連續存儲的,可是輸出的散列碼確實同樣的???。
條款11:優先採用foreach循環語句
c#1.0以上則第一個最好(c#1.0的化 第二個最好【由於第一個由裝箱】)。
在1.0版本的編譯器產生的代碼中,在數組上使用foreach語句其實是經過IEnumerator接口來遍歷數組,而這會致使裝箱與拆箱操做:遍歷類型=(遍歷類型)Current(接口類型); 1.0之後用的是for來遍歷的
foreach語法簡潔 自帶finally{ dispose() } 釋放內存 。
擴展: Unity5.5版本以後修復了foreach的GC http://www.mamicode.com/info-detail-2103245.html
第三個最差:
緣由解析:安全託管環境中每一個內存都會檢查,而經過將Length變量放到循環以外,實際上阻礙了JIT編譯器移除循環中的範圍檢查。
反編譯後:
CLR 會在訪問每個特定數組元素以前,產生一個數組界限(並不是上面的len變量)測試。C#編譯器和JIT編譯器能夠確保循環中的數組界限是安全的。只要循環變量不是數組的Length屬性,每一次迭代時都會執行數組界限檢查。破壞了JIT自己的優化
《編寫高質量代碼改善C#程序的157個建議》
string:
1. 值類型轉string時,須要重寫ToString(),使其調用值類型中的ToString()方法。由於值類型中的ToString()時非託管代碼,能夠直接操做內存來完成操做,效率高不少。
2. 字符串拼接時,使用StringBuilder。若是沒有先定義長度的話,則默認分配長度未16。當字符串小於16時,不會重寫分配。32>=str>=16時,則重寫分配,使之成爲16的倍數。注意指定的長度搖合適,過小須要頻繁分配內存。
3. Format格式化,內部是使用的stringbuilder.
枚舉:最好不要賦值 , 若是賦值的話最好從0開始
4.重載運算符:
用戶本身定義的運算方式,通常用於對幾個對象之間內部進行的一些操做。
5. 重寫Equals時也要重寫GetHashCode
若是自定義對象被用做基於散列集合的鍵,則建議重寫Equals方法。查詢時是基於key值的HashCode來查找鍵值的。【若是須要全部new的對象當成一個key,即須要重寫HashCode(),包裝一個int值的HashCode來看成該對象建立的全部對象的HashCode();
字符串不一樣到那時產生的HashCode()是同樣的狀況和緣由。獲得的哈希值是int型,而若是是字符串,字符串的長度和這個值的大小是正比,過長的字符串會致使這個值超過int.max,因此會哈希值同樣的狀況,解決方案是在這個哈希值的前邊把方法名加上。
14. 正確實現淺拷貝和深拷貝
淺拷貝: 值類型拷貝的是值 引用類型拷貝的是引用
深拷貝: 值類型拷貝的是值 引用類型拷貝的是引用指向的值
第2章 集合和LINQ
16. 元素數量可變的狀況下不該該使用數組
不要讓數組成爲大對象【>85000字節數】,大對象的回收效率低
17.多數狀況下使用foreach遍歷
理由:語法簡潔 自帶finally{ dispose() } 釋放內存 。
for[索引器實現的] foreach(迭代器實現)
foreach不應修改內部元素的緣由: foreach對集合版本進行判斷,任何對集合的增刪改查都會使版本號+1 . MoveNext() 會進行版本號的檢查,有變更時會拋出異常【System.InvalidOperationException】。
通常使用匿名函數或者lambda 來對數據進行查詢
第三章 泛型、委託和事件
32 老是優先使用泛型
若T指向的數據類型是一致的,那麼泛型對象間能夠共享靜態成員。可是爲了規避混淆,泛型中要避免申明靜態成員。
泛型方法: 非泛型類型中的泛型方法,並不會在運行時的本地代碼中生成不一樣的類型。
泛型參數增長該泛型參數的行爲。編碼時多考慮對泛型進行約束
使用default爲泛型類型變量指定初始值:
當返回值是一個泛型類型時,則
37 . 使用lambda表達式代替匿名方法:
38. 當心閉包中的陷阱。
閉包: 指可以讀取其餘函數內部變量的函數。
所謂閉包對象:若是匿名方法(Lambda)引用了某個局部變量(在for中),編輯器就會自動將該對象引用提高到閉包對象中。
這樣即便代碼執行後離開了局部變量i的做用域【如for循環】,包含該閉包對象的做用於也還存在。
上述代碼避免閉包:
閉包的實現過程: 經過捕獲變量來實現的閉包。
40. 泛型參數兼容泛型接口的不可變型 泛型的可變性// 基礎不夠之後再研究 ???
協變: 讓返回值類型返回比聲明的類型派生程度【子類比父類派生程度大】更大的類型,就是協變。
逆變:方法的參數能夠是委託或者泛型接口的參數類型的基類。
out在c#4.0 新增功能,能夠在泛型接口和委託中使用,用來讓類型支持協變。
除非考慮到該委託聲明確定不會用於可變性,不然爲委託中的泛型參數指定out關鍵字將會擴展該委託的應用。
public delegate TResult Func<out TResult>();
第四章 資源管理
託管資源: 由CLR管理和分配
非託管:不受CLR 管理的對象,套接字,文件,數據庫連接,windows內核,com對象
53.必要時應將再也不使用的對象的引用賦值爲null
引用賦值爲null 沒 必要的狀況:
局部變量和方法的參數變量,不管咱們是否在方法內部將局部變量賦值爲null,a=null該語句會被忽略。這也說明JIT編譯器是一個優化過的編譯器。若是是Release模式,則a=null都不會編譯進運行時。
引用賦值爲null必要的狀況:
靜態字段,好比建立一個對象,該對象中有靜態字段,當該局部變量對象被釋放後,該對象中的靜態字段不會被釋放。由於靜態字段建立後,該「根」就一直存在。因此手動置爲null. 這也是最好少用靜態字段的緣由。
54. 爲無用字段標註不可序列化
55.利用定製特性減小可序列化的字段
第6章 異步 多線程 任務 並行
71. 區分異步和多線程應用場景
DMA(Direct Memory Access): 直接內存訪問,是一種不通過CPU而直接進行內存數據存儲的數據交換模式。幾乎不損耗CPU. CLR異步編程模型就是充分利用DMA功能釋放CPU壓力。
多線程本質: 建立一個線程,一直等待獲取數據,一直佔着CPU資源。線程不是一個計算機硬件的功能,而是操做系統提供的一種邏輯功能,線程本質上是進程中一段併發運行的代碼,因此線程須要操做系統投入CPU資源來運行和調度。
異步本質:開始異步操做時,CLR把工做交給線程池中的某個線程進行完成。當開始IO操做時,異步會把工做線程還給線程池。至關於獲取工做不會再佔用CPU資源,直到異步完成,獲取數據結束後,異步纔會通知回調的方式通知線程池。先幹別的事,當它須要的數據準備完畢後,再會來幹這件事。
計算 密集型工做: 多線程,(例如耗時較長的圖形處理和算法執行)
IO 密集型工做: 採用異步機制。(文件,網絡數據修改,數據庫操做、Web Service、HttpRequest以及.Net Remoting等跨進程的調用)
多線程建立線程,一直等待,獲取數據,獲取完畢。異步線程池中的線程,等待。開始IO操做時,還給線程池,獲取完畢後回調。
異步,讓線程池中的一個線程獲取網頁,獲取後開始IO操做(讀取網頁),此時把線程還給線程池,直到異步完成,即獲取網頁完畢後,異步纔會經過回調的方式通知線程池。
72. 在線程同步中使用的信號量
EventWaitHandle 維護一個內核產生的布爾類型對象(「阻滯狀態」),若是值=false,那麼在上邊等待的線程就阻塞【應用程序域內的線程同步】
Semaphore: 維護一個內核產生的整形變量。值=0,則在上邊等待的線程就阻塞。>0解除阻塞,每解除一個其值減1.【應用程序域內的線程同步】
Mutex : 能夠跨域阻塞和解除阻塞。
lock鎖注意點:
1. 主要是鎖對象,不能鎖值類型【值拷貝方式】 ,
2. 不能鎖字符串,沒有必要並且很危險【若是兩個變量分配了相同內容的字符串,那麼兩個引用指的同一個內存,用了鎖後,實際鎖的時同一個對象,會致使程序崩潰】
3. 不能寫成lock(this) 會new幾個對象,達不到鎖定的目的。
同步鎖時很耗費時的。線程池中的線程默認是後臺線程。 建立的線程默認是前臺線程【默認isbackground=false 前臺線程不退出,應用程序的進程則一直存在,要殺死】
75. 線程並非實時當即啓動
76.警戒線程的優先級
77. 正確中止線程
問題: 和啓動線程同樣,不是想停就馬上停的。得幹完手頭要緊的活,好比如今在執行非託管代碼,引起異常得回到託管代碼中。
線程中止主要取決於工做線程是否能主動訪問調用者的中止請求。
標準的取消模式:協議式取消。
CancellationTokenSource cts=new CancellationTokenSource();
cts.Token.Register(fun()); //線程中止時的回調
cts.Cancel(); //發送Cancel信號 線程中止
socket 1000臺客戶端異步技術 只需幾個線程就能夠了(取決於心跳頻率)
79. 使用TreadPool或BackgroundWorker代替Thread
80. Task代替ThreadPool
ThreadPool: 不支持線程的取消,完成,失敗通知。不支持線程執行的前後順序。
81. Parallel簡化同步狀態
82. 並行
第二部分 架構篇
第7章 成員設計
90.
<1 . 不要爲抽象類提供公開的構造方法,抽象類設計只是爲了繼承,而不是用於生成實例對象
<2. 可見字段應該重構爲屬性,屬性和字段的區別:一個是方法,一個是字段
<3. 謹慎把數組或者集合做爲屬性
<4. 構造方法應初始化主要屬性和字段。【一個貓生下來就已經具有尾巴了】
<5. 區別對待override和new.[new 重寫覆蓋了父類方法,至關於該類中的一個新方法,和父類中的方法沒有一點關係]
<6. 避免在構造方法中調用虛方法
<7. 成員優先考慮公開基類型或者接口
<8 . 用params減小重複參數
<9. 重寫時不該該使用子類參數
建議100: 靜態方法和實例方法沒有區別
101. 使用擴展方法,向現有類型「添加」方法
第八章 類型設計
103. 區分組合和繼承的應用場合
組合; 在新類A中聲明 類B,C,D的實例。【有一個的概念】
107. 區分靜態類和單例
靜態類不是一個真正的對象,可是單例類時一個對象。
109. 謹慎使用嵌套類
當某一個類須要訪問另外一個類型的私有成員時,才實現爲嵌套類
111. 避免雙重耦合【常見的解耦就是提煉接口】
112. 把現實世界中的對象抽象爲類【貓,狗】,將可複用對象圈起來就是命名空間【植物,動物】
第9章 安全性設計
考慮可能出現的最大值:定義加工資,最大值。checked{} 關鍵字i行覈實,會主動拋出異常
114. MD5 再也不安全 【窮舉法破解】
115. HASH 檢驗文件是否被纂改
116. 避免非對稱算法加密
117. ......
<1. Company.Component 命名空間命名
<2. 考慮命名空間使用複數,System.Books 不要System.AllBook
<3. 用名詞和名詞組給類型命名 推薦ScoreManager 不要SoreManage
<4. 考慮讓派生類的名字以基類名字做爲後綴
<5. 泛型類型參數要以T做爲前綴
<6. 以複數命名枚舉類型,以單數命名枚舉元素【Week 不要Day】
<7. 用camelCasing命名私有字段和局部變量
<8. 常量如下劃線的方式 TASK_STATE_CANCELED s_ 靜態變量
<9. 考慮使用確定性的短語命名bool屬性 IsEnabled
<10.優先使用後綴做爲一個類型的信版本,不到不得已並不推薦 Book1 Book2
<11. 委託和事件加上上級後綴 HttpDelegate()
<12. 事件處理器函數採用組合式命名: Button_SizeChanged()
代碼整潔的要求之一,就是儘可能減小代碼。如省略默認的訪問修飾符
<1. 使用表驅動法避免過長的if和switch分支
<2. 使用匿名方法,Lambda表達式代替方法 若是方法體小於3行
<3. 使用事件訪問器替換公開的事件成員變量
寫在開頭:
http://www.cnblogs.com/luminji 157個建議_勘誤表
一:屬性
屬性和方法同樣。也能夠是virtual和abstract.
運行時常量優於編譯時常量【能正確運行纔是關鍵】。編譯時常量比運行時常量稍微塊一點,可是缺少靈活性。性能很是關鍵,其值永遠不變的狀況下,咱們才應該使用編譯時常量。
c# readonly 運行時常量【構造器一旦執行則不能對值進行修改】 const編譯時常量
編譯時常量編譯後會把該常量替換成常量的值,相似於c++的宏【編譯時常量只能夠用於基元類型(整數浮點數枚舉字符串)】。運行時編譯後任然是該變量的引用
操做符as和is都只檢查被轉換對象的運行時類型,並不執行其餘的操做。若是被轉換對象的運行時類型既不是所轉換的目標類型,也不是其派生類型,那麼轉型將告失敗
as操做符不能用於值類型,int值類型,不能爲null.
as是直接轉
只有當咱們不能使用as操做符來進行類型轉換時,才應該使用is操做符。
若是咱們打算使用as來作轉型,那麼再使用is檢查就沒有必要了。直接將as操做符的運算結果和null進行比對就能夠了,這樣比較簡單
c# is和as的區別
is就是處於對類型的判斷。返回true和false。若是一個對象是某個類型或是其父類型的話就返回爲true,不然的話就會返回爲false。另外is操做符永遠不會拋出異常。代碼以下:
若是對象引用爲null,那麼is操做符老是返回爲false,由於沒有對象能夠檢查其類型,就像下面代碼同樣
if(o is Employee)
{
Employee e = (Employee) o;
//在if語句中使用e
}
as :as必須和能夠爲NUll類型使用。轉int則不行
Employee e = o as Employee;
if(e != null)
{
//在if語句中使用e
}
這種as操做即使等同於上面代碼,同時只進行了1次的類型檢查,因此提升了性能。若是類型相同就返回一個非空的引用,不然就返回一個空引用。
條款4:使用Conditional特性代替#if條件編譯
條款5:老是提供ToString()方法
條款6:明辨值類型和引用類型的使用場合
值類型用於存儲數據,引用類型用於定義行爲
條款7:將值類型儘量實現爲具備常量性和原子性的類型
枚舉將None=0聲明出來
ReferenceEquals(): 無論比較的是引用類型仍是值類型,該方法都判斷的是「引用相等」,而非「值相等」,意味着若是咱們使用此來比較兩個值類型,其結果永遠返回false。即便咱們將一個值類型和自身進行比較,ReferenceEquals()的返回值還是false。致使這種結果的緣由在於裝箱
Object.Equals() 默認是引用判斷,可是值類型例外,判斷值類型時須要重寫Equals()方法。若是兩個值類型變量的類型相同,而且內容一致,這兩個變量才被認爲相等。
判斷是否引用的同一個對象時的注意點: string a="aa"; string b = "aa"; 兩個比較都是相等的。這是由於系統並無給字符串b分配內存,只是將"aa"指向了b。因此a和b指向的是同一個字符串(字符串在這種賦值的狀況下作了內存的優化)
相等的數學屬性:自反(任何對象都與其自身相等)、對稱(相等判斷的順序是可有可無的)和可傳遞(a=b b=c 則a=c)
條款10:理解GetHashCode()方法的缺陷
注意; a="aa" b="aa" unity中能夠經過散列碼GetHashCode()間接的查看兩個變量的地址是否相等,可是數組的地址是連續存儲的,可是輸出的散列碼確實同樣的???。
條款11:優先採用foreach循環語句
c#1.0以上則第一個最好(c#1.0的化 第二個最好【由於第一個由裝箱】)。
在1.0版本的編譯器產生的代碼中,在數組上使用foreach語句其實是經過IEnumerator接口來遍歷數組,而這會致使裝箱與拆箱操做:遍歷類型=(遍歷類型)Current(接口類型); 1.0之後用的是for來遍歷的
foreach語法簡潔 自帶finally{ dispose() } 釋放內存 。
擴展: Unity5.5版本以後修復了foreach的GC http://www.mamicode.com/info-detail-2103245.html
第三個最差:
緣由解析:安全託管環境中每一個內存都會檢查,而經過將Length變量放到循環以外,實際上阻礙了JIT編譯器移除循環中的範圍檢查。
反編譯後:
CLR 會在訪問每個特定數組元素以前,產生一個數組界限(並不是上面的len變量)測試。C#編譯器和JIT編譯器能夠確保循環中的數組界限是安全的。只要循環變量不是數組的Length屬性,每一次迭代時都會執行數組界限檢查。破壞了JIT自己的優化
《編寫高質量代碼改善C#程序的157個建議》
string:
1. 值類型轉string時,須要重寫ToString(),使其調用值類型中的ToString()方法。由於值類型中的ToString()時非託管代碼,能夠直接操做內存來完成操做,效率高不少。
2. 字符串拼接時,使用StringBuilder。若是沒有先定義長度的話,則默認分配長度未16。當字符串小於16時,不會重寫分配。32>=str>=16時,則重寫分配,使之成爲16的倍數。注意指定的長度搖合適,過小須要頻繁分配內存。
3. Format格式化,內部是使用的stringbuilder.
枚舉:最好不要賦值 , 若是賦值的話最好從0開始
4.重載運算符:
用戶本身定義的運算方式,通常用於對幾個對象之間內部進行的一些操做。
5. 重寫Equals時也要重寫GetHashCode
若是自定義對象被用做基於散列集合的鍵,則建議重寫Equals方法。查詢時是基於key值的HashCode來查找鍵值的。【若是須要全部new的對象當成一個key,即須要重寫HashCode(),包裝一個int值的HashCode來看成該對象建立的全部對象的HashCode();
字符串不一樣到那時產生的HashCode()是同樣的狀況和緣由。獲得的哈希值是int型,而若是是字符串,字符串的長度和這個值的大小是正比,過長的字符串會致使這個值超過int.max,因此會哈希值同樣的狀況,解決方案是在這個哈希值的前邊把方法名加上。
14. 正確實現淺拷貝和深拷貝
淺拷貝: 值類型拷貝的是值 引用類型拷貝的是引用
深拷貝: 值類型拷貝的是值 引用類型拷貝的是引用指向的值
第2章 集合和LINQ
16. 元素數量可變的狀況下不該該使用數組
不要讓數組成爲大對象【>85000字節數】,大對象的回收效率低
17.多數狀況下使用foreach遍歷
理由:語法簡潔 自帶finally{ dispose() } 釋放內存 。
for[索引器實現的] foreach(迭代器實現)
foreach不應修改內部元素的緣由: foreach對集合版本進行判斷,任何對集合的增刪改查都會使版本號+1 . MoveNext() 會進行版本號的檢查,有變更時會拋出異常【System.InvalidOperationException】。
通常使用匿名函數或者lambda 來對數據進行查詢
第三章 泛型、委託和事件
32 老是優先使用泛型
若T指向的數據類型是一致的,那麼泛型對象間能夠共享靜態成員。可是爲了規避混淆,泛型中要避免申明靜態成員。
泛型方法: 非泛型類型中的泛型方法,並不會在運行時的本地代碼中生成不一樣的類型。
泛型參數增長該泛型參數的行爲。編碼時多考慮對泛型進行約束
使用default爲泛型類型變量指定初始值:
當返回值是一個泛型類型時,則
37 . 使用lambda表達式代替匿名方法:
38. 當心閉包中的陷阱。
閉包: 指可以讀取其餘函數內部變量的函數。
所謂閉包對象:若是匿名方法(Lambda)引用了某個局部變量(在for中),編輯器就會自動將該對象引用提高到閉包對象中。
這樣即便代碼執行後離開了局部變量i的做用域【如for循環】,包含該閉包對象的做用於也還存在。
上述代碼避免閉包:
閉包的實現過程: 經過捕獲變量來實現的閉包。
40. 泛型參數兼容泛型接口的不可變型 泛型的可變性// 基礎不夠之後再研究 ???
協變: 讓返回值類型返回比聲明的類型派生程度【子類比父類派生程度大】更大的類型,就是協變。
逆變:方法的參數能夠是委託或者泛型接口的參數類型的基類。
out在c#4.0 新增功能,能夠在泛型接口和委託中使用,用來讓類型支持協變。
除非考慮到該委託聲明確定不會用於可變性,不然爲委託中的泛型參數指定out關鍵字將會擴展該委託的應用。
public delegate TResult Func<out TResult>();
第四章 資源管理
託管資源: 由CLR管理和分配
非託管:不受CLR 管理的對象,套接字,文件,數據庫連接,windows內核,com對象
53.必要時應將再也不使用的對象的引用賦值爲null
引用賦值爲null 沒 必要的狀況:
局部變量和方法的參數變量,不管咱們是否在方法內部將局部變量賦值爲null,a=null該語句會被忽略。這也說明JIT編譯器是一個優化過的編譯器。若是是Release模式,則a=null都不會編譯進運行時。
引用賦值爲null必要的狀況:
靜態字段,好比建立一個對象,該對象中有靜態字段,當該局部變量對象被釋放後,該對象中的靜態字段不會被釋放。由於靜態字段建立後,該「根」就一直存在。因此手動置爲null. 這也是最好少用靜態字段的緣由。
54. 爲無用字段標註不可序列化
55.利用定製特性減小可序列化的字段
第6章 異步 多線程 任務 並行
71. 區分異步和多線程應用場景
DMA(Direct Memory Access): 直接內存訪問,是一種不通過CPU而直接進行內存數據存儲的數據交換模式。幾乎不損耗CPU. CLR異步編程模型就是充分利用DMA功能釋放CPU壓力。
多線程本質: 建立一個線程,一直等待獲取數據,一直佔着CPU資源。線程不是一個計算機硬件的功能,而是操做系統提供的一種邏輯功能,線程本質上是進程中一段併發運行的代碼,因此線程須要操做系統投入CPU資源來運行和調度。
異步本質:開始異步操做時,CLR把工做交給線程池中的某個線程進行完成。當開始IO操做時,異步會把工做線程還給線程池。至關於獲取工做不會再佔用CPU資源,直到異步完成,獲取數據結束後,異步纔會通知回調的方式通知線程池。先幹別的事,當它須要的數據準備完畢後,再會來幹這件事。
計算 密集型工做: 多線程,(例如耗時較長的圖形處理和算法執行)
IO 密集型工做: 採用異步機制。(文件,網絡數據修改,數據庫操做、Web Service、HttpRequest以及.Net Remoting等跨進程的調用)
多線程建立線程,一直等待,獲取數據,獲取完畢。異步線程池中的線程,等待。開始IO操做時,還給線程池,獲取完畢後回調。
異步,讓線程池中的一個線程獲取網頁,獲取後開始IO操做(讀取網頁),此時把線程還給線程池,直到異步完成,即獲取網頁完畢後,異步纔會經過回調的方式通知線程池。
72. 在線程同步中使用的信號量
EventWaitHandle 維護一個內核產生的布爾類型對象(「阻滯狀態」),若是值=false,那麼在上邊等待的線程就阻塞【應用程序域內的線程同步】
Semaphore: 維護一個內核產生的整形變量。值=0,則在上邊等待的線程就阻塞。>0解除阻塞,每解除一個其值減1.【應用程序域內的線程同步】
Mutex : 能夠跨域阻塞和解除阻塞。
lock鎖注意點:
1. 主要是鎖對象,不能鎖值類型【值拷貝方式】 ,
2. 不能鎖字符串,沒有必要並且很危險【若是兩個變量分配了相同內容的字符串,那麼兩個引用指的同一個內存,用了鎖後,實際鎖的時同一個對象,會致使程序崩潰】
3. 不能寫成lock(this) 會new幾個對象,達不到鎖定的目的。
同步鎖時很耗費時的。線程池中的線程默認是後臺線程。 建立的線程默認是前臺線程【默認isbackground=false 前臺線程不退出,應用程序的進程則一直存在,要殺死】
75. 線程並非實時當即啓動
76.警戒線程的優先級
77. 正確中止線程
問題: 和啓動線程同樣,不是想停就馬上停的。得幹完手頭要緊的活,好比如今在執行非託管代碼,引起異常得回到託管代碼中。
線程中止主要取決於工做線程是否能主動訪問調用者的中止請求。
標準的取消模式:協議式取消。
CancellationTokenSource cts=new CancellationTokenSource();
cts.Token.Register(fun()); //線程中止時的回調
cts.Cancel(); //發送Cancel信號 線程中止
socket 1000臺客戶端異步技術 只需幾個線程就能夠了(取決於心跳頻率)
79. 使用TreadPool或BackgroundWorker代替Thread
80. Task代替ThreadPool
ThreadPool: 不支持線程的取消,完成,失敗通知。不支持線程執行的前後順序。
81. Parallel簡化同步狀態
82. 並行
第二部分 架構篇
第7章 成員設計
90.
<1 . 不要爲抽象類提供公開的構造方法,抽象類設計只是爲了繼承,而不是用於生成實例對象
<2. 可見字段應該重構爲屬性,屬性和字段的區別:一個是方法,一個是字段
<3. 謹慎把數組或者集合做爲屬性
<4. 構造方法應初始化主要屬性和字段。【一個貓生下來就已經具有尾巴了】
<5. 區別對待override和new.[new 重寫覆蓋了父類方法,至關於該類中的一個新方法,和父類中的方法沒有一點關係]
<6. 避免在構造方法中調用虛方法
<7. 成員優先考慮公開基類型或者接口
<8 . 用params減小重複參數
<9. 重寫時不該該使用子類參數
建議100: 靜態方法和實例方法沒有區別
101. 使用擴展方法,向現有類型「添加」方法
第八章 類型設計
103. 區分組合和繼承的應用場合
組合; 在新類A中聲明 類B,C,D的實例。【有一個的概念】
107. 區分靜態類和單例
靜態類不是一個真正的對象,可是單例類時一個對象。
109. 謹慎使用嵌套類
當某一個類須要訪問另外一個類型的私有成員時,才實現爲嵌套類
111. 避免雙重耦合【常見的解耦就是提煉接口】
112. 把現實世界中的對象抽象爲類【貓,狗】,將可複用對象圈起來就是命名空間【植物,動物】
第9章 安全性設計
考慮可能出現的最大值:定義加工資,最大值。checked{} 關鍵字i行覈實,會主動拋出異常
114. MD5 再也不安全 【窮舉法破解】
115. HASH 檢驗文件是否被纂改
116. 避免非對稱算法加密
117. ......
<1. Company.Component 命名空間命名
<2. 考慮命名空間使用複數,System.Books 不要System.AllBook
<3. 用名詞和名詞組給類型命名 推薦ScoreManager 不要SoreManage
<4. 考慮讓派生類的名字以基類名字做爲後綴
<5. 泛型類型參數要以T做爲前綴
<6. 以複數命名枚舉類型,以單數命名枚舉元素【Week 不要Day】
<7. 用camelCasing命名私有字段和局部變量
<8. 常量如下劃線的方式 TASK_STATE_CANCELED s_ 靜態變量
<9. 考慮使用確定性的短語命名bool屬性 IsEnabled
<10.優先使用後綴做爲一個類型的信版本,不到不得已並不推薦 Book1 Book2
<11. 委託和事件加上上級後綴 HttpDelegate()
<12. 事件處理器函數採用組合式命名: Button_SizeChanged()
代碼整潔的要求之一,就是儘可能減小代碼。如省略默認的訪問修飾符
<1. 使用表驅動法避免過長的if和switch分支
<2. 使用匿名方法,Lambda表達式代替方法 若是方法體小於3行
<3. 使用事件訪問器替換公開的事件成員變量