為啥你的編譯型程序和人家解釋型一程序樣慢?(一) ——寫在前面的話——性能分析點(diǎn)。
?
公司拿回了被外包到印度的一個(gè)項(xiàng)目,C#代碼,我沒事看看的時(shí)候,發(fā)現(xiàn)這么一個(gè)函數(shù)(有修改)
?
static string RandomString(int length)
{
Random random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
?
就是從某個(gè)字符集中隨機(jī)產(chǎn)生一個(gè)字符串,讓我們看看這堆狗屎到底做了什么。
首先字符集是 chars,然后要產(chǎn)生字符串結(jié)果的長度是length,這段代碼將字符集復(fù)制了length次,然后從每一個(gè)副本中隨機(jī)取一個(gè)組成一個(gè)列表,然后new 成一個(gè)字符串。各位吐了沒有?還好這個(gè)字符集,只有26+10個(gè)。要整一個(gè)Unicode的話,這段代碼直接要便秘了。 我直接想到的是有這么一種改進(jìn):?
?
static string MyRandomString1(int length)
{
Random random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Range(0, length)
.Select(i => chars[random.Next(chars.Length)]).ToArray());
}
至少,這段代碼不用復(fù)制字符集???
我直接把兩個(gè)函數(shù)調(diào)用1萬次,length=10000。然后一比。什么?居然耗時(shí)差不多?(此處我放一個(gè)書簽,也就是我們這篇文章的point)。
當(dāng)時(shí)我認(rèn)為,C# release 優(yōu)化的還不錯(cuò)啊。于是乎寫下第二個(gè) 鄉(xiāng)民版
? static string MyRandomString2(int length)
{
Random random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
sb.Append(chars[random.Next(chars.Length)]);
}
return sb.ToString();
}
?
果然這段代碼在性能是輕松碾壓上兩個(gè)。Intel 公司長舒一口氣,果然 你是我的最好代言,要想使用語言新特性,請買酷睿最新第八代!
?
性能提升總是最誘人的,我下意識的想 如果用C++再寫一遍,這幫C#代碼要屁滾尿流到什么程度?
?
于是我就寫了寫,寫C++的時(shí)候慢了很多,因?yàn)槲疫€在乎性能,不能像C#那個(gè)隨意拉隨意撒了
?
string cppRandom(int length) {
static string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static auto random = bind(uniform_int_distribution(0, chars.length() - 1), default_random_engine());
string res;
res.resize(length);
for (int i = 0; i < length; ++i) {
res[i] = chars[random()];
}
return res;
}
寫完后,滿心歡喜的運(yùn)行,結(jié)果發(fā)現(xiàn) 只比前兩個(gè)linq版本 快不到四倍,比 鄉(xiāng)民版快不到兩倍。
才快一倍多,尼瑪我受打擊了,用不到linq,還要自己鏟屎,才給我快不到兩倍?。。?!
如果牛掰的人現(xiàn)在已經(jīng)知道原因了,這也是我前面留書簽的地方。我不賣乖了,原因就是,
。
。
。
。
。
。
。
。
。
。
。
。
。
這么多函數(shù)貌似測試的是隨機(jī)數(shù)產(chǎn)生器的性能!是不是 恍然大悟?是不是茅塞頓開?是不是有所回想?
這也就是本系列文章的引子,說起代碼快慢,比較的時(shí)候最好不要參雜其他因素,上面的例子引入了隨機(jī)數(shù)在測試函數(shù)里,就是問題。
于是乎,我就把幾萬(一萬個(gè)太小了)個(gè)隨機(jī)數(shù)先生成出來放在數(shù)組里,然后再測試,結(jié)果終于滿意了。本文所有涉及代碼只貼片段,不提供完整代碼。你是碼農(nóng),不就是寫代碼的么?你應(yīng)該還要感謝我,所有代碼沒有上截圖。。。。
我從來不和別人爭辯哪個(gè)語言好,你說你哪個(gè)語言好,大不了我就用C/C++把你的編譯器,解釋器虛擬機(jī)寫出來,然后嵌入我的項(xiàng)目里(其實(shí)寫都不用寫,可能就是開源的,還是C/C++代碼),再寫寫你那個(gè)語言的代碼,反正寫著也很快(不用擔(dān)心鏟屎什么的)。
?
當(dāng)然,在某些特定情況下解釋語言也很快,比如python的正則表達(dá)式解析匹配很快,幾乎可以匹敵C++。所以,我現(xiàn)在經(jīng)常把python嵌入到我的項(xiàng)目里,才幾兆~
?
?
?