IronPython和C#執(zhí)行速度對(duì)比
我構(gòu)思的實(shí)驗(yàn)覆蓋到下面幾個(gè)我認(rèn)為是實(shí)際項(xiàng)目中比較有代表性的場(chǎng)景:
1.訪問(wèn)一個(gè)稍大的數(shù)據(jù)表,遍歷所有記錄;
2.生成并操作一個(gè)列表;
3.生成并操作一個(gè)字典;
4.通過(guò)反射動(dòng)態(tài)加載并調(diào)用一個(gè)方法。
C#部分的代碼,編譯時(shí)使用了/debug-和/optimize+:
Code
- usingSystem;
- usingSystem.Data.SqlClient;
- usingSystem.Diagnostics;
- usingSystem.Collections.Generic;
- usingSystem.Reflection;
- namespaceTest
- {
- classTest
- {
- publicstaticvoidMain(string[]args)
- {
- Console.WriteLine("C#:");
- Measure(TestDb,"TestDb");
- Measure(TestList,"TestList");
- Measure(TestDict,"TestDict");
- Measure(TestReflection,"TestReflection");
- }
- delegatevoidFuncDelegate();
- staticvoidMeasure(FuncDelegatefunc,stringfuncName)
- {
- Stopwatchsw=newStopwatch();
- sw.Start();
- func();
- sw.Stop();
- Console.WriteLine("{0}used{1}ms",funcName,sw.ElapsedMilliseconds);
- }
- staticvoidTestDb()
- {
- using(SqlConnectionconn=newSqlConnection(connStr))
- {
- conn.Open();
- SqlCommandcmd=newSqlCommand(sql,conn);
- SqlDataReaderreader=cmd.ExecuteReader();
- while(reader.Read())
- {
- varid=reader["Id"];
- varcode=reader["Code"];
- varcargoCode=reader["CargoCode"];
- varlength=reader["Length"];
- varwidth=reader["Width"];
- varheight=reader["Height"];
- varvol=reader["Vol"];
- varpallet=reader["Pallet"];
- }
- reader.Close();
- cmd.Dispose();
- conn.Close();
- }
- }
- staticvoidTestList()
- {
- varlist=newList();
- constintcount=100000;
- for(inti=0;ilist.Add(string.Format("item{0}",i));
- for(inti=count-1;i>=0;i--)
- list.RemoveAt(i);
- }
- staticvoidTestDict()
- {
- vardict=newDictionary();
- constintcount=100000;
- for(inti=0;idict[string.Format("key{0}",i)]=string.Format("value{0}",i);
- for(inti=0;idict.Remove(string.Format("key{0}",i));
- }
- staticvoidTestReflection()
- {
- AssemblyAssemblyassem=Assembly.LoadFrom("Lib.dll");
- Typetype=assem.GetType("Lib.TestLib");
- constintcount=100000;
- ConstructorInfoci=type.GetConstructor(Type.EmptyTypes);
- MethodInfomi=type.GetMethod("GetMessage");
- for(inti=0;i{
- objectobj=ci.Invoke(null);//Activator.CreateInstance(type);
- mi.Invoke(obj,newobject[]{"name"});
- }
- }
- conststringconnStr="IntegratedSecurity=SSPI;InitialCatalog=test;DataSource=.";
- conststringsql="select*fromCargoPackageTypes";
- }
- }
IronPython部分的代碼:
Code
- from__future__importwith_statement
- importclr,sys
- clr.AddReference('System.Data')
- fromSystem.Data.SqlClientimportSqlCommand,SqlConnection
- fromSystem.DiagnosticsimportStopwatch
- fromSystem.ReflectionimportAssembly
- connStr="IntegratedSecurity=SSPI;InitialCatalog=test;DataSource=.";
- sql="select*fromCargoPackageTypes";
- deftestDb():
- withSqlConnection(connStr)asconn:
- conn.Open()
- cmd=SqlCommand(sql,conn)
- reader=cmd.ExecuteReader()
- whilereader.Read():
- id=reader["Id"]
- code=reader["Code"]
- cargoCode=reader["CargoCode"]
- length=reader["Length"]
- width=reader["Width"]
- height=reader["Height"]
- vol=reader["Vol"]
- pallet=reader["Pallet"]
- reader.Close()
- cmd.Dispose()
- conn.Close()
- deftestList():
- lst=[]
- count=100000
- foriinxrange(count):
- lst.append('item%d'%i)
- foriinxrange(count-1,-1,-1):
- lst.pop(i)
- deftestDict():
- d={}
- count=100000
- foriinxrange(count):
- d['key%d'%i]='value%d'%i
- foriinxrange(count):
- d.pop('key%d'%i)
- deftestReflection():
- clr.AddReferenceToFile('Lib.dll')
- fromLibimportTestLib
- count=100000
- foriinxrange(count):
- obj=TestLib()
- obj.GetMessage('name')
- defmeasure(fn):
- sw=Stopwatch()
- sw.Start()
- fn()
- sw.Stop()
- print'%sused%sms'%(fn.__name__,sw.ElapsedMilliseconds)
- print'Python:'
- measure(testDb)
- measure(testList)
- measure(testDict)
- measure(testReflection)
運(yùn)行結(jié)果:
對(duì)于列表和字典的操作,IronPython比C#慢3到4倍,這是意料之中的事情。沒(méi)有想到的是訪問(wèn)數(shù)據(jù)庫(kù)的方法,IronPython竟然比C#還要略快,這是事先無(wú)論如何都沒(méi)有料到的。原來(lái)我以為,數(shù)據(jù)庫(kù)訪問(wèn)代碼基本上是純粹的調(diào)用ADO.Net,瓶頸主要是在數(shù)據(jù)庫(kù)那一邊,IronPython在方法調(diào)用的時(shí)候應(yīng)該比C#略微慢一點(diǎn)吧,那么總體速度也應(yīng)該稍微慢一點(diǎn)才對(duì)。沒(méi)想到結(jié)果正好反過(guò)來(lái)!我也沒(méi)有辦法解釋為什么這里IronPython能夠做到比C#還快。不過(guò)結(jié)論應(yīng)該很明顯了:訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候,你無(wú)需擔(dān)心IronPython不夠快。我們的項(xiàng)目大多數(shù)時(shí)候效率瓶頸都是出在數(shù)據(jù)庫(kù)上面,至于程序語(yǔ)言快一點(diǎn)還是慢一點(diǎn)通常無(wú)關(guān)緊要,更何況這里的結(jié)果表明腳本語(yǔ)言有時(shí)候反而可能更快呢。
對(duì)于反射的測(cè)試,IronPython則是壓倒性的戰(zhàn)勝了C#。需要說(shuō)明的一點(diǎn)是我在C#中反射生成對(duì)象使用的方法是ConstructorInfo.Invoke()。如果換成Activator.CreateInstance()的話(huà),那么C#的時(shí)間將會(huì)縮減到230~250毫秒,不過(guò)即便這樣仍然比IronPython落后一半左右。為什么使用反射時(shí)IronPython比C#快這么多呢?或許因?yàn)樗\(yùn)行的時(shí)候能夠在內(nèi)存中動(dòng)態(tài)生成部分字節(jié)碼,從而跳過(guò)反射環(huán)節(jié),所以更快吧。
從這個(gè)實(shí)驗(yàn)的結(jié)果看,IronPython的性能可以說(shuō)好到超出了我的預(yù)期。因?yàn)橹耙部催^(guò)其他一些相關(guān)的性能評(píng)測(cè),比如說(shuō)Ruby要比Java的運(yùn)行速度慢30倍(這個(gè)比較已經(jīng)有一段時(shí)間了,現(xiàn)在差距應(yīng)該有所縮?。?,相比之下IronPython的性能簡(jiǎn)直可以用十分優(yōu)異來(lái)形容了。當(dāng)然腳本語(yǔ)言也有一個(gè)不足的地方,就是加載解釋器的時(shí)候會(huì)帶來(lái)幾秒鐘的固定開(kāi)銷(xiāo),頻繁修改程序的時(shí)候,這幾秒鐘還是有點(diǎn)讓人難受的。好在以嵌入方式使用IronPython的時(shí)候,引擎只需要加載一次就夠了,所以這個(gè)缺點(diǎn)大體上還是可以接受的。
【編輯推薦】