當前位置:
首頁 > 知識 > C 配置文件存儲 各種序列化演算法性能比較

C 配置文件存儲 各種序列化演算法性能比較

本文比較多個方式進行配置文件的存儲,對比各個不同演算法的讀寫性能。

在應用軟體啟動的時候,需要讀取配置文件,但是啟動的性能很重要,所以需要有一個很快的讀取配置文件的方法。

如果你不想看過程,那麼請看拖動滾動條

本文將會比較三個世界上最好的序列化演算法,一個是 json 、一個是 ProtoBuf 、一個是 wire

原來我的軟體在啟動的時候是需要讀取很多個文件,因為每個模塊的配置都不同,所有模塊的配置都是模塊自己查找配置文件讀取,然而大家都知道,在機械硬碟,隨機讀取文件的性能很差。現在雖然很多用戶都是使用固態硬碟,但是對於啟動性能優化,還是要盡量減少在軟體啟動過程的讀取文件。

我詢問了奎爺,他是一位強大的程序員,他告訴我,谷歌瀏覽器把很多零碎的文件,如歷史記錄和密碼都壓縮為一個文件,這樣的啟動時候,順序讀取性能很快,所以瀏覽器才可以快速啟動。

於是我就開始了準備把所有的模塊的配置文件合為一個,在合併的時候需要做序列化,因為存在很多模塊都是使用自己實現的方式進行序列化。

下面就是我進行對比各個演算法的性能。

需要注意,在軟體啟動的時候,還需要計算 dll 載入的性能,也就是如果有一個dll可以提高序列化性能,但是這個 dll 載入性能很差,也是不能使用這個dll的。

定義

先定義一個簡單的類,這個類用來存放數據,只有 key-value 的數據

[ProtoContract]
[Serializable]
public class Foo
{
[ProtoMember(1)]
public Dictionary<string, string> CurmobeKallbu { set; get; }
}
1
2
3
4
5
6
7

在啟動之前就需要讀取這個文件作為配置,所以需要找到一個很快的方法從文件讀取,然後反序列化。

為了方便序列化,我寫了一個方法Foo.BegaymouniWaloujijou用來創建 1000 個隨機的 key-value 為數據。因為代碼很多,我就不寫了,下面就是函數的定義,需要大家寫入隨機的值

public static Foo BegaymouniWaloujijou()
{
return new Foo()
{
CurmobeKallbu = new Dictionary<string, string>()
{
// 這裡寫入隨機的值
}
};
}
1
2
3
4
5
6
7
8
9
10

json

首先是使用最有名的 json 來進行序列化,安裝 Nuget 第一個,點擊管理nuget,然後點擊瀏覽,現在看到的第一個是不是 json 庫?如果不是,那麼說明本文已經過期

在看本文的時候,如果要運行本文的代碼,需要先在自己的 E 盤創建一個叫回收站的文件夾。因為我在代碼會對這個文件夾寫入。

var fileInfo = new FileInfo(@"E:回收站xx5");
if (!fileInfo.Exists)
{
var foo = Foo.BegaymouniWaloujijou();
var stopwatch = new Stopwatch();
stopwatch.Start();
using (var stream = new StreamWriter(fileInfo.OpenWrite()))
{
var str = JsonConvert.SerializeObject(foo, Formatting.Indented);
stream.Write(str);
}
stopwatch.Stop();
Console.WriteLine("寫入" + stopwatch.ElapsedMilliseconds);
}
else
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenText();
using (stream)
{
var foo = JsonConvert.DeserializeObject<Foo>(stream.ReadToEnd());
}
stopwatch.Stop();
Console.WriteLine("讀取時間" + stopwatch.ElapsedMilliseconds);
fileInfo.Delete();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

上面的代碼很簡單,就是使用這個方式保存

那麼性能怎樣?請看下面

讀取 寫入
170 188
161 150
191 168
166 164
230 156
1
2
3
4
5
6

數據的單位是毫秒,平均時間是讀取 183.6 毫秒,寫入165.2毫秒

ProtoBuf

這是 谷歌的一個庫,我安裝了 protobuf-net ,然後進行序列化

C 配置文件存儲 各種序列化演算法性能比較

var fileInfo = new FileInfo(@"E:回收站xx2");
if (!fileInfo.Exists)
{
var foo = Foo.BegaymouniWaloujijou();
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenWrite();
using (stream)
{
Serializer.Serialize(stream, foo);
}
stopwatch.Stop();
Console.WriteLine("寫入" + stopwatch.ElapsedMilliseconds);
}
else
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenRead();
using (stream)
{
stream.Seek(0, SeekOrigin.Begin);
var foo = Serializer.Deserialize<Foo>(stream);
}
stopwatch.Stop();
Console.WriteLine("讀取時間" + stopwatch.ElapsedMilliseconds);
fileInfo.Delete();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

我嘗試在 ssd 和 機械硬碟讀寫,比較兩個的性能

下面是在 ssd 的讀寫性能,平均時間是讀取 91.8 毫秒,寫入 119.4 毫秒

讀取 寫入
90 108
84 115
93 142
80 109
112 123
1
2
3
4
5
6

我嘗試在機械硬碟讀寫,平均時間是讀取104.4毫秒,寫入140.2毫秒

讀取 寫入
95 127
115 163
107 168
98 128
107 115
1
2
3
4
5
6

wire

這是傳說中最快的序列化庫,我安裝了 Wire 然後使用下面的代碼,運行 5 次計算讀寫時間

var fileInfo = new FileInfo(@"E:回收站xx3");
if (!fileInfo.Exists)
{
var foo = Foo.BegaymouniWaloujijou();
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenWrite();
using (stream)
{
var serializer = new Wire.Serializer();
serializer.Serialize(foo, stream);
}
stopwatch.Stop();
Console.WriteLine("寫入" + stopwatch.ElapsedMilliseconds);
}
else
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenRead();
using (stream)
{
var serializer = new Wire.Serializer();
var foo = serializer.Deserialize<Foo>(stream);
}
stopwatch.Stop();
Console.WriteLine("讀取時間" + stopwatch.ElapsedMilliseconds);
fileInfo.Delete();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

雖然小夥伴說他是最快的,但是在我的設備,平均讀取125.8毫秒,寫入101.2毫秒

讀取 寫入
109 104
106 94
111 92
190 90
113 126
1
2
3
4
5
6

自己寫的

最後我嘗試自己寫了簡單的序列化,因為存放的信息是key-value,我可以控制包含的字元串都是不帶換行,也就是我可以一行放 value 一行放關鍵字。

var fileInfo = new FileInfo(@"E:回收站xx7");
if (!fileInfo.Exists)
{
var foo = Foo.BegaymouniWaloujijou();
var stopwatch = new Stopwatch();
stopwatch.Start();
using (var stream = new StreamWriter(fileInfo.OpenWrite()))
{
foreach (var temp in foo.CurmobeKallbu)
{
stream.WriteLine(temp.Key);
stream.WriteLine(temp.Value);
}
}
stopwatch.Stop();
Console.WriteLine("寫入" + stopwatch.ElapsedMilliseconds);
}
else
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = fileInfo.OpenText();
using (stream)
{
var str = stream.ReadToEnd().Split("
");
var foo = new Foo();
foo.CurmobeKallbu = new Dictionary<string, string>(str.Length / 2);
string key = null;
foreach (var temp in str)
{
if (key == null)
{
key = temp;
}
else
{
foo.CurmobeKallbu.Add(key, temp);
key = null;
}
}
}
stopwatch.Stop();
Console.WriteLine("讀取時間" + stopwatch.ElapsedMilliseconds);
fileInfo.Delete();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

我發現在 ssd 和在機械硬碟讀寫性能幾乎沒有相差,有時候相同程序在 ssd 運行的時間比在機械硬碟多。在我測試了自己寫的程序才知道,最多的時間在序列化,讀取文件的時間反而可以被忽略。使用自己寫的序列化讀取1毫秒,寫入7.2毫秒,所以這麼簡單的配置文件還是自己做序列化比較快。

讀取 寫入
1 6
1 8
1 8
1 5
1 9
1
2
3
4
5
6

建議

在軟體啟動的時候,還有一個讀取文件是載入庫,如果我使用了第三方的 dll ,那麼在啟動的時候我就需要載入這個 dll ,但是我讀取的配置文件只有不到 100 k 但是我載入的幾個庫都是很大。載入庫的時間已經足夠我自己寫的序列化讀取完成,需要知道,在啟動程序的時候不是把所有程序的庫都載入,只有在用到的時候才去讀取庫,讀取庫也是需要時間,所以程序啟動的時候盡量不要引用不相關的庫。

C 配置文件存儲 各種序列化演算法性能比較

所以在啟動的過程如果需要讀取配置文件,還是使用自己寫序列化,而且要求自己寫的配置文件很穩定,不要在啟動的時候出現異常。

自己寫配置文件可以在一個線程進行讀取,然後把整個程序所有在啟動過程使用配置文件的地方都刪除,只有軟體啟動的過程讀取的文件只有很少的幾個,最好是一個,這樣才能保證軟體啟動的性能。

代碼:C# 配置文件存儲 各種序列化演算法性能比較 程序1.1-CSDN下載

如果沒有積分需要代碼請聯繫我

C 配置文件存儲 各種序列化演算法性能比較

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

Python 異常處理
構建 Hadoop 集群

TAG:程序員小新人學習 |