<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入理解string和如何高效地使用string

      無論你所使用的是哪種編程語言,我們都不得不承認這樣一個共識:string是我們使用最為頻繁的一種對象。但是string的常用性并不意味著它的簡單性,而且我認為,正是由于string的頻繁使用才會促使其設計人員在string的設計上花大量的功夫。所以正是這種你天天見面的string,蘊含了很多精妙的設計思想。

      一個月以前我寫了一篇討論字符串的駐留(string interning)的文章,我今天將會以字符串的駐留為基礎,進一步來討論.NET中的string。string interning的基本前提是string的恒定性(immutability),即string一旦被創建將不會改變。我們就先來談談string的恒定性。

      一、      string是恒定的(immutable)

      和其他類型比較,string最為顯著的一個特點就是它具有恒定不變性:我們一旦創建了一個string,在managed heap 上為他分配了一塊連續的內存空間,我們將不能以任何方式對這個string進行修改使之變長、變短、改變格式。所有對這個string進行各項操作(比如調用ToUpper獲得大寫格式的string)而返回的string,實際上另一個重新創建的string,其本身并不會產生任何變化。

      String的恒定性具有很多的好處,它首先保證了對于一個既定string的任意操作不會造成對其的改變,同時還意味著我們不用考慮操作string時候出現的線程同步的問題。在string恒定的這些好處之中,我覺得最大的好處是:它成就了字符串的駐留。

      CLR通過一個內部的interning table保證了CLR只維護具有不同字符序列的string,任何具有相同字符序列的string所引用的均為同一個string對象,同一段為該string配分的內存快。字符串的駐留極大地較低了程序執行對內存的占用。

      對于string的恒定性和字符串的駐留,還有一點需要特別指出的是:string的恒定性不單單是針對某一個單獨的AppDomain,而是針對一個進程的。

      二、      String可以跨AppDomain共享的(cross-appDomain)

      我們知道,在一個托管的環境下,Appdomain是托管程序運行的一個基本單元。AppDomain為托管程序提供了良好的隔離機制,保證在同一個進程中的不同的Appdomain不可以共享相同的內存空間。在一個Appdomain創建的對象不能被另一個Appdomain直接使用,對象在AppDomain之間傳遞需要有一個Marshaling的過程:對象需要通過by reference或者by value的方式從一個Appdomain傳遞到另一個Appdomain。具體內容可以參照我的另一篇文章:用Coding證明Appdomain的隔離性

      但是這里有一個特例,那就是string。Appdomain的隔離機制是為了防止一個Application的對內存空間的操作對另一個Application 內存空間的破壞。通過前面的介紹,我們已經知道了string是恒定不變的、是只讀的。所以它根本不需要Appdomain的隔離機制。所以讓一個恒定的、只讀的string被同處于一個進程的各個Application共享是沒有任何問題的。

      String的這種跨AppDomain的恒定性成就了基于進程的字符串駐留:一個進程中各個Application使用的具有相同字符序列的string都是對同一段內存的引用。我們將在下面通過一個Sample來證明這一點。

      三、      證明string垮AppDomain的恒定性

      在寫這篇文章的時候,我對如何證明string跨AppDomain的interning,想了好幾天,直到我偶然地想到了為實現線程同步的lock機制。

      我們知道在一個多線程的環境下,為了避免并發操作導致的數據的不一致性,我們需要對一個對象加鎖來阻止該對象被另一個線程 操作。相反地,為了證明兩個對象是否引用的同一個對象,我們只需要在兩個線程中分別對他們加鎖,如果程序執行的效果和對同一個對象加鎖的情況完全一樣的話,那么就可以證明這兩個被加鎖的對象是同一個對象。基于這樣的原理我們來看看我們的Sample:

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Threading;

      namespace Artech.ImmutableString
      {
          
      class Program
          
      {
              
      static void Main(string[] args)
              
      {
                  AppDomain appDomain1 
      = AppDomain.CreateDomain("Artech.AppDomain1");
                  AppDomain appDomain2 
      = AppDomain.CreateDomain("Artech.AppDomain2");

                  MarshalByRefType marshalByRefObj1 
      = appDomain1.CreateInstanceAndUnwrap("Artech.ImmutableString""Artech.ImmutableString.MarshalByRefType"as MarshalByRefType;
                  MarshalByRefType marshalByRefObj2 
      = appDomain2.CreateInstanceAndUnwrap("Artech.ImmutableString""Artech.ImmutableString.MarshalByRefType"as MarshalByRefType;

                  marshalByRefObj1.StringLockHelper 
      = "Hello World";
                  marshalByRefObj2.StringLockHelper 
      = "Hello World";

                  Thread thread1 
      = new Thread(new ParameterizedThreadStart(Execute));
                  Thread thread2 
      = new Thread(new ParameterizedThreadStart(Execute));

                  thread1.Start(marshalByRefObj1);
                  thread2.Start(marshalByRefObj2);

                  Console.Read();            
              }


              
      static void Execute(object obj)
              

                  MarshalByRefType marshalByRefObj 
      = obj as MarshalByRefType;
                  marshalByRefObj.ExecuteWithStringLocked();
              }

          }


          
      class MarshalByRefType : MarshalByRefObject
          
      {
              
      Private Fields

              
      Public Properties

              
      Public Methods
          }

      }

      我們來簡單地分析一下上面的coding.

      我們創建了一個繼承自MarshalByRefObject,因為我需要讓它具有跨AppDomain傳遞的能力。在這個Class中定義了兩個為實現線程同步的helper字段,一個是string類型的_stringLockHelper和object類型的_objectLockHelper,并為他們定義了相應的Property。此外定義了兩個方法:ExecuteWithStringLocked和ExecuteWithStringLocked,他們的操作類似:在先對_stringLockHelper和_objectLockHelper加鎖的前提下,輸出出操作執行的AppDomain和確切時間。我們通過調用Thread.Sleep模擬10s的時間延遲。

      在Main方法中,首先創建了兩個AppDomain,名稱分別為Artech.AppDomain1和Artech.AppDomain2。隨后在這兩個AppDomain中創建兩個MarshalByRefType對象,并為它們的StringLockHelper屬性賦上相同的值:Hello World。最后,我們創建了兩個新的線程,并在它們中分別調用在兩個不同AppDomain 中創建的MarshalByRefType對象的ExecuteWithStringLocked方法。我們來看看運行后的輸出結果:

       

      從上面的輸出結果中可以看出,兩個分別在不同線程中執行操作對應的AppDomain的name分別為Artech.AppDomain1和Artech.AppDomain2。執行的時間(確切地說是操作成功地對MarshalByRefType對象的_stringLockHelper字段進行加鎖的時間)相隔10s,也就是我們在程序中定義的時間延遲。

      為什么會出現這樣的結果呢?我們只是對兩個處于不同AppDomain的不同的MarshalByRefType對象的stringLockHelper字段進行加鎖。由于我們是同時開始他們對應的線程,照理說它們之間不會有什么關聯,顯示出來的時間應該是相同的。唯一的解釋就是:雖然這兩個在不同的AppDomain中創建的對象是兩個完全不同的對象,由于他們的stringLockHelper字段具有相同的字符序列,它們引用的是同一個string。這就證明了我們提出的跨AppDomain進行string interning的結論。

      為了進一步印證我們的結論,我們是使兩個MarshalByRefObject對象的stringLockHelper字段具有不同的值,看看結果又如何。于是我們把其中一個對象的stringLockHelper字段改為”Hello World!”(多加了一個!) 。

      marshalByRefObj1.StringLockHelper = "Hello World";
      marshalByRefObj2.StringLockHelper 
      = "Hello World!";

      看看現在的輸出結果,現在的時間是一樣了。


      上面我們做的是對string類型字段加鎖的試驗。那么我們對其他類型的對象進行加鎖,又會出現怎么的情況呢?我們現在就來做這樣試驗:在各自的線程中調用兩個對象的ExecuteWithObjectLocked方法。我們修改Execute方法和Main()。

      static void Execute(object obj)
              

                  MarshalByRefType marshalByRefObj 
      = obj as MarshalByRefType;
                  marshalByRefObj. ExecuteWithObjectLocked ();
      }

      static void Main(string[] args)
              
      {
                  AppDomain appDomain1 
      = AppDomain.CreateDomain("Artech.AppDomain1");
                  AppDomain appDomain2 
      = AppDomain.CreateDomain("Artech.AppDomain2");

                  MarshalByRefType marshalByRefObj1 
      = appDomain1.CreateInstanceAndUnwrap("Artech.ImmutableString""Artech.ImmutableString.MarshalByRefType"as MarshalByRefType;
                  MarshalByRefType marshalByRefObj2 
      = appDomain2.CreateInstanceAndUnwrap("Artech.ImmutableString""Artech.ImmutableString.MarshalByRefType"as MarshalByRefType;

                  
      object obj = new object();
                  marshalByRefObj1.ObjectLockHelper 
      = obj;
                  marshalByRefObj2.ObjectLockHelper 
      = obj;

                  Thread thread1 
      = new Thread(new ParameterizedThreadStart(Execute));
                  Thread thread2 
      = new Thread(new ParameterizedThreadStart(Execute));

                  thread1.Start(marshalByRefObj1);
                  thread2.Start(marshalByRefObj2);

                  Console.Read();            
              }

      我們先來看看運行后的輸出結果:


      我們發現兩個時間是一樣的,那么就是說兩個對象的ObjectLockHelper引用的不是同一個對象。雖然上面的程序很簡單,我覺得里面涉及的規程卻很值得一說。我們來分析下面3段代碼。

      object obj = new object();
      marshalByRefObj1.ObjectLockHelper 
      = obj;
      marshalByRefObj2.ObjectLockHelper 
      = obj;

      簡單看起來,兩個MarshalByRefObject對象的ObjectLockHelper都是引用的同一個對象obj。但是背后的情況沒有那么簡單。代碼第一行創建了一個新的對象obj,這個對象是在當前AppDomain 中創建的。二對于當前的AppDomain來說,marshalByRefObj1和marshalByRefObj2僅僅是一個Transparent proxy而已,它們包含一個在Artech.AppDomain1和Artech.AppDomain2中創立的MarshalByRefObject對象的引用。我們為它的ObjectLockHelper復制,對于Transparent proxy對象的賦值調用會傳到真正對象所在的AppDomain,由于obj是當前AppDomain的對象,它不能直接賦給另一個AppDomain的對象。所以它必須經歷一個Marshaling的過程才能被傳遞到另外一個AppDomain。實際上當復制操作完成之后,真正的ObjectLockHelper屬性對應的對象是根據原數據重建的對象,和在當前AppDomain中的對象已經沒有任何的關系。所以兩個MarshalByRefObject對象的ObjectLockHelper屬性引用的并不是同一個對象,所以對它進行加鎖對彼此不要產生任何影響。

      四、      從Garbage Collection的角度來看string

      我們知道在一個托管的環境下,一個對象的生命周期被GC管理和控制。一個對象只有在他不被引用的時候,GC才會對他進行垃圾回收。而對于一個string來說,它始終被interning table引用,而這個interning table是針對一個Process的,是被該Process所有AppDomain共享的,所以一個string的生命周期相對比較長,只有所有的AppDomain都不具有對該string的引用時,他才有可能被垃圾回收。

      五、      從多線程的角度來看string

      一方面由于string的恒定性,我們不用考慮多線程的并發操作產生的線程同步問題。另一方面由于字符串的駐留,我們在對一個string對象進行加鎖操作的時候,極有可能拖慢這個Application的performance,就像我們的Sample中演示的那樣。而且很有可能影響到處于同一進程的其他Application,以致造成死鎖。所以我們在使用鎖的時候,除非萬不得已,切忌對一個string進行加鎖。

      六、      如何高效地使用string

      下面簡單介紹一些高效地使用string的一些小的建議:

      1. 盡量使用字符串(literal string)相加來代替字符串變量和字符創相加,因為這樣可以使用現有的string操作指令進行操作和利用字符串駐留。

      比如:

      string s = "abc" + "def";

      優于

      string s = "abc";
      = s + "def";

      2. 在需要的時候使用StringBuilder對string作頻繁的操作:

      由于string的恒定性,在我們對一個string進行某些操作的時候,比如調用ToUpper()或者ToLower()把某個string每個字符轉化成大寫或者小寫;調用SubString()取子串;會創建一個新的string,有時候會創建一些新的臨時string。這樣的操作會增加內存的壓力。所有在對string作頻繁操作的情況下,我們會考慮使用StringBuilder來高效地操作string。StringBuilder之所以能對string操作帶來更好的performance,是因為在它的內部維護一個字符數組,而不是一個string來避免string操作帶來的新的string的創建。

      StringBuilder是一個很好的字符累加器,我們應該充分地利用這一個功能:

      StringBuilder sb = new StringBuilder();
      sb.Append(str1 
      + str2);

      最好寫成

      StringBuilder sb = new StringBuilder();
      sb.Append(str1);
      sb.Append(str2);

      避免創建一個新的臨時string來保存str1 + str2。

      再比如下面的Code

      StringBuilder sb = new StringBuilder();
      sb.Append(WorkOnString1());
      sb.Append(WorkOnString2());
      sb.Append(WorkOnString3());

      最好寫好吧WorkOnString1,WorkOnString2,WorkOnString3定義成:

      WorkOnString1(StringBuilder sb)
      WorkOnString2(StringBuilder sb)
      WorkOnString3(StringBuilder sb)

      3. 高效地進行string的比較操作

      我們知道,對象之間的比較有比較Value和比較Reference之說。一般地對Reference進行比較的速度最快。對于string,在字符串駐留的前提下,我們可以把對Value的比較用Reference的比較來代替從而會的Performance的提升。

      此外,對于忽略大小寫的比較,我們最好使用string的static方法Compare(string strA, string strB, bool ignoreCase)。也就是說:

      if(str1.ToLower()==str2.ToLower())

      最好寫成

      If(string. Compare(str1,str2,true))
      posted @ 2007-05-06 15:30  Artech  閱讀(20635)  評論(60)    收藏  舉報
      主站蜘蛛池模板: 大名县| 亚洲精品动漫一区二区三| 国产一区二区丰满熟女人妻| 日本不卡三区| 国产95在线 | 欧美| 九九热在线免费视频精品| 亚洲精品天堂在线观看| 久久人人妻人人爽人人爽| 开心久久综合激情五月天| 国产女人在线视频| 男女猛烈激情xx00免费视频| 国产精品先锋资源在线看| 亚洲无线观看国产精品| 国内自拍小视频在线看| 亚洲男人AV天堂午夜在| 沂南县| 亚洲一区二区三区在线| 色综合亚洲一区二区小说| 少妇人妻偷人精品无码视频新浪| 无人区码一码二码三码区| 人妻少妇偷人精品一区| 国内精品卡一卡二卡三| 搡老女人老妇女老熟妇| 国产三级a三级三级| 国产av综合色高清自拍| 精品国产高清中文字幕| 国产精品爽爽爽一区二区| 精品中文人妻中文字幕| 中文字幕亚洲无线码A| 九九热视频在线观看一区| 在线观看国产一区亚洲bd| 国产极品尤物粉嫩在线观看| 国产边摸边吃奶边叫做激情视频 | 亚洲高清 一区二区三区| 亚洲av无码牛牛影视在线二区 | 最新精品露脸国产在线| 国产一区二区三区不卡观| 乱中年女人伦av二区| 国产精品蜜臀av在线一区| 国产中文三级全黄| 白丝乳交内射一二三区|