最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C# StringBuilder內(nèi)存碎片對(duì)性能的影響

 更新時(shí)間:2020年03月22日 11:13:04   作者:.NET操作  
這篇文章主要介紹了淺談StringBuilder內(nèi)存碎片對(duì)性能的影響,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

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

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

背景

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

測(cè)試方法

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)于這段代碼,請(qǐng)注意以下幾點(diǎn):

  • 通過(guò).PadRight(n)來(lái)直接創(chuàng)建長(zhǎng)度為n的空白字符串,可以用new string(' ', n)來(lái)代替;
  • new Random(42)處,我指定了一個(gè)隨機(jī)因子,確保每次分隔后分隔的位置完全相同,有利于做對(duì)照組;
  • 我分別對(duì)字符串進(jìn)行了2^1 ~ 2^16次修改,分別比較經(jīng)過(guò)這么多次修改之后的性能差異;
  • 我使用sb[i]來(lái)逐一訪問(wèn)StringBuilder中的位置,使內(nèi)存不連續(xù)性更加突顯。

運(yùn)行結(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ìn)行大量修改,其性能會(huì)急據(jù)下降,注意看32768次修改的情況下,遍歷時(shí)會(huì)產(chǎn)生高達(dá)1630.4倍的性能差!

解決方式

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

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);
    
    // 重點(diǎn)
    const int defragmentCount = 250;
    if (i % defragmentCount == defragmentCount - 1)
    {
      string buf = sb.ToString();
      sb.Clear();
      sb.Append(buf);
    }
  }
}

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

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ù)造成的訪問(wèn)性能問(wèn)題,解決——同時(shí)250可能是一個(gè)相對(duì)比較合理的數(shù)字,在插入性能與查詢/遍歷性能中,獲得平衡。

反思與總結(jié)

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

StringBuilder這樣做成鏈?zhǔn)降慕Y(jié)構(gòu)并非沒(méi)有原因,如果考慮插入性能,做成鏈?zhǔn)浇涌谑亲顑?yōu)秀的。但如果考慮查詢性能,鏈?zhǔn)浇Y(jié)構(gòu)就非常不利了,如果設(shè)計(jì)為非鏈?zhǔn)浇Y(jié)構(gòu),從中間插入時(shí),StringBuilder的內(nèi)存空間可能不夠,因此需要重新分配內(nèi)存,這樣相當(dāng)于將StringBuilder降格為string,因此完全喪失了StringBuilder適合做“頻繁插入”的優(yōu)勢(shì)。

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

到此這篇關(guān)于淺談StringBuilder內(nèi)存碎片對(duì)性能的影響的文章就介紹到這了,更多相關(guān)StringBuilder 內(nèi)存碎片內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入分析C#鍵盤勾子(Hook),屏蔽鍵盤活動(dòng)的詳解

    深入分析C#鍵盤勾子(Hook),屏蔽鍵盤活動(dòng)的詳解

    本篇文章是對(duì)C#鍵盤勾子(Hook),屏蔽鍵盤活動(dòng)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C# 添加對(duì)System.Configuration.dll文件的引用操作

    C# 添加對(duì)System.Configuration.dll文件的引用操作

    這篇文章主要介紹了C# 添加對(duì)System.Configuration.dll文件的引用操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • 在Winform動(dòng)態(tài)啟動(dòng)、控制臺(tái)命令行的方法

    在Winform動(dòng)態(tài)啟動(dòng)、控制臺(tái)命令行的方法

    winForm 程序輸出類型為 windows 程序(不是命令行程序)在運(yùn)行時(shí)想輸入一些信息編譯開發(fā)調(diào)試,如何實(shí)現(xiàn)這一功能
    2013-02-02
  • C# 使用HttpClient上傳文件并附帶其他參數(shù)的步驟

    C# 使用HttpClient上傳文件并附帶其他參數(shù)的步驟

    這篇文章主要介紹了C# 使用HttpClient上傳文件并附帶其他參數(shù)的步驟,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • c#數(shù)據(jù)類型基礎(chǔ)

    c#數(shù)據(jù)類型基礎(chǔ)

    C#里面的數(shù)據(jù)類型分為兩種:值類型和引用類型。
    2008-08-08
  • C#關(guān)機(jī)小程序源碼

    C#關(guān)機(jī)小程序源碼

    這是用所學(xué)習(xí)的C#做的一個(gè)關(guān)機(jī)小程序,功能不多,只是為了練手,需要的朋友可以參考下
    2012-10-10
  • C#圖表開發(fā)之Chart詳解

    C#圖表開發(fā)之Chart詳解

    C#中的Chart控件用于開發(fā)圖表功能,具有Series和ChartArea兩個(gè)重要屬性,Series屬性是SeriesCollection類型,包含多個(gè)Series對(duì)象,每個(gè)Series代表圖表中的一個(gè)數(shù)據(jù)系列,Series對(duì)象有一個(gè)Points屬性,用于存儲(chǔ)數(shù)據(jù)點(diǎn),每個(gè)數(shù)據(jù)點(diǎn)是一個(gè)DataPoint對(duì)象
    2024-12-12
  • C#生成唯一不重復(fù)訂單號(hào)

    C#生成唯一不重復(fù)訂單號(hào)

    本文給大家介紹的是使用C#生成唯一不重復(fù)訂單號(hào)的方法,主要用到了lock鎖,有需要的小伙伴可以參考下。
    2015-07-07
  • C#讀取寫入文件的3種方式示例代碼

    C#讀取寫入文件的3種方式示例代碼

    最近操作文件頻繁,所以這篇文章主要給大家介紹了關(guān)于C#讀取寫入文件的3種方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-06-06
  • WPF實(shí)現(xiàn)動(dòng)畫效果(一)之基本概念

    WPF實(shí)現(xiàn)動(dòng)畫效果(一)之基本概念

    這篇文章介紹了WPF實(shí)現(xiàn)動(dòng)畫效果之基本概念,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評(píng)論

绥滨县| 洞口县| 顺平县| 大姚县| 南漳县| 兴文县| 青海省| 大安市| 博野县| 苗栗县| 黎城县| 南川市| 泾源县| 香港| 家居| 虎林市| 苗栗县| 奎屯市| 嘉义县| 武隆县| 云霄县| 崇义县| 竹溪县| 壶关县| 大竹县| 吉安市| 乌鲁木齐市| 金寨县| 东乡族自治县| 新乐市| 海淀区| 秦安县| 治多县| 新竹县| 清水河县| 沅陵县| 南丹县| 固阳县| 保康县| 横山县| 桃源县|