中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

C#中StringBuilder內(nèi)存碎片對性能的影響有哪些

這篇文章將為大家詳細講解有關(guān)C#中StringBuilder內(nèi)存碎片對性能的影響有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

在民權(quán)等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè) 網(wǎng)站設(shè)計制作按需設(shè)計網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站建設(shè),成都營銷網(wǎng)站建設(shè),外貿(mào)網(wǎng)站制作,民權(quán)網(wǎng)站建設(shè)費用合理。

StringBuilder內(nèi)部是由多段char[]組成的半自動鏈表,因此頻繁從中間修改StringBuilder,會將原本連續(xù)的內(nèi)存分隔為多段,從而影響讀取/遍歷性能。

連續(xù)內(nèi)存與不連續(xù)內(nèi)存的性能差,可能高達1600倍。

背景

用StringBuilder的用戶可能大都想用StringBuilder拼接html/json模板、組裝動態(tài)SQL等正常操作。但在一些特殊場景中——如為某種編程語言寫語言服務(wù),或者寫一個富文本編輯器時,StringBuilder依然也有用武之地,通過里面的Insert/Remove兩個方法來修改。

測試方法

Talk is cheap, show me the code:

int docLength = 10000;
void Main()
{
  (from power in Enumerable.Range (1, 16)
  let mutations = (int) Math.Pow (2, power)
  select new
  {
    mutations,
    PerformanceRatio = Math.Round (GetPerformanceRatio (docLength, mutations), 1)
  }).Dump();
}

float GetPerformanceRatio (int docLength, int mutations)
{
  var sb = new StringBuilder ("".PadRight (docLength));
  var before = GetPerformance (sb);
  FragmentStringBuilder (sb, mutations);
  var after = GetPerformance (sb);
  return (float) after.Ticks / before.Ticks;
}

void FragmentStringBuilder (StringBuilder sb, int mutations)
{
  var r = new Random(42);
  for (int i = 0; i < mutations; i++)
  {
    sb.Insert (r.Next (sb.Length), 'x');
    sb.Remove (r.Next (sb.Length), 1);
  }
}

TimeSpan GetPerformance (StringBuilder sb)
{
  var sw = Stopwatch.StartNew();
  long tot = 0;
  for (int i = 0; i < sb.Length; i++)
  {
    char c = sb[i];
    tot += (int) c;
  }
  sw.Stop();
  return sw.Elapsed;
}

關(guān)于這段代碼,請注意以下幾點:

  • 通過.PadRight(n)來直接創(chuàng)建長度為n的空白字符串,可以用new string(' ', n)來代替;

  • new Random(42)處,我指定了一個隨機因子,確保每次分隔后分隔的位置完全相同,有利于做對照組;

  • 我分別對字符串進行了2^1 ~ 2^16次修改,分別比較經(jīng)過這么多次修改之后的性能差異;

  • 我使用sb[i]來逐一訪問StringBuilder中的位置,使內(nèi)存不連續(xù)性更加突顯。

運行結(jié)果

mutationsPerformanceRatio
21
41
81
161
321
641.1
1281.2
2561.8
5125.2
102419.9
204881.3
4096274.5
8192745.8
163841578.8
327681630.4
65536930.8

可見如果在StringBuilder中間進行大量修改,其性能會急據(jù)下降,注意看32768次修改的情況下,遍歷時會產(chǎn)生高達1630.4倍的性能差!

解決方式

如果一定要用StringBuilder,可以考慮在修改一定次數(shù)后,重新創(chuàng)建一個新的StringBuilder,以使得訪問時獲得最佳的內(nèi)存連續(xù)性,即可解決此問題:

void FragmentStringBuilder (StringBuilder sb, int mutations)
{
  var r = new Random(42);
  for (int i = 0; i < mutations; i++)
  {
    sb.Insert (r.Next (sb.Length), 'x');
    sb.Remove (r.Next (sb.Length), 1);
    
    // 重點
    const int defragmentCount = 250;
    if (i % defragmentCount == defragmentCount - 1)
    {
      string buf = sb.ToString();
      sb.Clear();
      sb.Append(buf);
    }
  }
}

如上,每經(jīng)過250次修改,即將原StringBuilder刪除,然后重新創(chuàng)建一個新的StringBuilder,此時運行效果如下:

mutationsPerformanceRatio
21.2
40.7
81
161
321
641.1
1281.2
2561
5121
10241
20481
40961.1
81921.5
163841.3
327681
655361

可見,在幾乎所有情況下,受內(nèi)存不連續(xù)造成的訪問性能問題,解決——同時250可能是一個相對比較合理的數(shù)字,在插入性能與查詢/遍歷性能中,獲得平衡。

反思與總結(jié)

眾所周知,由于string的不可變性,拼接大量字符串時,會浪費大量內(nèi)存。但使用StringBuilder也需要了解它的結(jié)構(gòu)。

StringBuilder這樣做成鏈式的結(jié)構(gòu)并非沒有原因,如果考慮插入性能,做成鏈式接口是最優(yōu)秀的。但如果考慮查詢性能,鏈式結(jié)構(gòu)就非常不利了,如果設(shè)計為非鏈式結(jié)構(gòu),從中間插入時,StringBuilder的內(nèi)存空間可能不夠,因此需要重新分配內(nèi)存,這樣相當于將StringBuilder降格為string,因此完全喪失了StringBuilder適合做“頻繁插入”的優(yōu)勢。

本文說的其實是一個非常特殊的例子,現(xiàn)實中除了語言服務(wù)、編輯器外,很少會需要這種即要頻繁插入快,也要頻繁修改快的場景。如果想簡單點搞,用StringBuilder會是一個有條件合適的解決方案。更適合的解決方案當然是專門的數(shù)據(jù)結(jié)構(gòu)——PieceTable,微軟在VSCode編輯器中,為了確保大文件編輯性能,使用了該數(shù)據(jù)結(jié)構(gòu),取得了非常不錯的成果,參考鏈接:Text Buffer Reimplementation。

關(guān)于“C#中StringBuilder內(nèi)存碎片對性能的影響有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

當前名稱:C#中StringBuilder內(nèi)存碎片對性能的影響有哪些
鏈接URL:http://www.rwnh.cn/article46/peojhg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、品牌網(wǎng)站設(shè)計企業(yè)建站、做網(wǎng)站、網(wǎng)站收錄、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計公司
新化县| 盐源县| 额济纳旗| 阳朔县| 德安县| 申扎县| 长汀县| 拜城县| 曲阳县| 万源市| 万载县| 霍山县| 松江区| 噶尔县| 绥滨县| 宜章县| 启东市| 美姑县| 卢龙县| 平遥县| 宕昌县| 陈巴尔虎旗| 璧山县| 应城市| 佛学| 墨玉县| 霍林郭勒市| 永善县| 大同市| 荔浦县| 阜宁县| 巴彦淖尔市| 阳江市| 南投市| 扬中市| 托克逊县| 志丹县| 澄城县| 神农架林区| 南安市| 富民县|