參加一個.NET培訓後的若干筆記

來源:互聯網
上載者:User

1. 上午老師提到一個thread必須隸屬於某個appDomain,我覺得有點疑惑。簡單在網上找了找,下面的關於soft thread和hard thread的闡述是我比較信服的:
AppDomain是個靜態概念,只是限定了對象的邊界;線程是個動態概念,它可以運行在不同的AppDomain。
一個AppDomain內可以建立多個線程,但是不能限定這些線程只能在本AppDomain內執行代碼。

CLR中的System.Threading.Thread對象其實是個soft thread,它並不能被作業系統識別;作業系統能識別的是hard thread。
一個soft thread只屬於一個AppDomain,穿越AppDomain的是hard thread。當hard thread訪問到某個AppDomain時,一個AppDomain就會為之產生一個soft thread。

hard thread有thread local storage(TLS),這個儲存區被CLR用來儲存這個hard thread當前對應的AppDomain引用以及soft

thread引用。當一個hard thread穿越到另外一個AppDomain時,TLS中的這些引用也會改變。

 

2.關於程式集的“熱插拔”

楊老師提到過保持程式集對外介面穩定可以實現程式集的“熱插拔”(即在不停止主應用程式的前提下,動態替換單個程式集)。下來查了一下,這種替換應該是 有很多條件的,因為.net不支援對單個程式集的Unload()操作,你必須把要替換的程式集放置在一個單獨的AppDomain中運行,替換程式集的時候要殺掉這個AppDomain,在一個新的AppDomain中Load新版本的程式集。

(AssemblyLoader.RemoteLoader)domain.CreateInstanceFromAndUnwrap(
                "AssemblyLoader.dll","AssemblyLoader.RemoteLoader"); 

所以,對這個程式集中方法的調用很多都將是跨邊界的遠程調用,效能上應該很成問題吧?有沒有哪位同志以前在項目中這樣用過?

 

3.雜湊/字典的底層結構是什嗎?其實就是數組,而根據key利用散列演算法計算出來的hashcode自然成為了數組的下標。
Hashtable用來存放資料的是bucket數組

[StructLayout(LayoutKind.Sequential)]
private struct bucket
{
    public object key;
    public object val;
    public int hash_coll;
}

而Dictionary<TKey,TValue>用來存放資料的是Entry數組(裡面多了一項next,同學們可以自己想想他用來做什麼^_^)

[StructLayout(LayoutKind.Sequential)]
private struct Entry
{
    public int hashCode;
    public int next;
    public TKey key;
    public TValue value;
}

既然是數組,那麼這個數組應該申請多大長度呢?即便你在建構函式中進行了指定,.net也不會完全以你指定的為準,而是會從素數表裡面找一個素數:

private void Initialize(int capacity)
{
    int prime = HashHelpers.GetPrime(capacity);
    this.buckets = new int[prime];
    for (int i = 0; i < this.buckets.Length; i++)
    {
        this.buckets[i] = -1;
    }
    this.entries = new Entry<TKey, TValue>[prime];
    this.freeList = -1;
}

那麼如果你插入的資料量很大,預先申請的數組不夠用了怎麼辦?擴容。
擴容是個耗時非常驚人的內部操作,Hashtable 之所以寫入效率僅為讀取效率的 1/10 數量級, 頻繁的擴容是一個因素。當進行擴容時,散列表內部要重新 new 一個更大的數組,然後把原來數組的內容拷貝到新數組,並進行重新散列。如何 new 這個更大的數組也有講究。散列表的初始容量一般來講是個素數。當擴容時,新數組的大小會設定成原數組雙倍大小的相近的一個素數。為了避免產生素數的額外開銷,.NET 內部有一個素數數組,記錄了常用到的素數。如下所示:
static HashHelpers()
{
    primes = new int[] { 
        3, 7, 11, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83, 0xa3, 0xc5, 0xef, 
        0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f, 0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, 0xd2b, 0xfd1, 0x12fd, 
        0x16cf, 0x1b65, 0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, 0x7655, 0x8e01, 0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 
        0x1a857, 0x1fd3b, 0x26315, 0x2dd67, 0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb, 0xec8c1, 0x11bdbf, 0x154a3f, 0x198c4f, 
        0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b, 0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89
     };
}

4. Delegate的序列化

今天楊老師還談到了代理序列化的問題。我們都知道代理後面可以掛一個很長的委託鏈,那序列化的時候這個委託鏈怎麼辦?google了一下,答案竟然是整個委託鏈都要被序列化,這就要求委託鏈上的每個對象都是可序列化的(要求很苛刻阿…)。所以,delegate的序列化要慎用。對了,還查到一個有趣的結果,以前沒注意到:

“delegate 開頭是小寫 d,如果換成大寫開頭的 Delegate,那差別可就大了,簡直是孫子和爺爺的區別。為什麼說是孫子和爺爺呢?因為 delegate 僅僅是 C# 的關鍵字,表示一個繼承自 System.MulticastDelegate 的具體委託類,而 Delegate 卻是  System.MulticastDelegate 的父類,這還不是孫子和爺爺嗎。另外,Delegate 和  System.MulticastDelegate 都是抽象類別,只有編譯器才可以從此類派生。也就是說,除了用 delegate 這種形式,我們不能顯式地從這兩個類派生。”

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.