我构思的实验覆盖到下面几个我认为是实际项目中比较有代表性的场景:
1.访问一个稍大的数据表,遍历所有记录;
2.生成并操作一个列表;
3.生成并操作一个字典;
4.通过反射动态加载并调用一个方法。
C#部分的代码,编译时使用了/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)
运行结果:
对于列表和字典的操作,IronPython比C#慢3到4倍,这是意料之中的事情。没有想到的是访问数据库的方法,IronPython竟然比C#还要略快,这是事先无论如何都没有料到的。原来我以为,数据库访问代码基本上是纯粹的调用ADO.Net,瓶颈主要是在数据库那一边,IronPython在方法调用的时候应该比C#略微慢一点吧,那么总体速度也应该稍微慢一点才对。没想到结果正好反过来!我也没有办法解释为什么这里IronPython能够做到比C#还快。不过结论应该很明显了:访问数据库的时候,你无需担心IronPython不够快。我们的项目大多数时候效率瓶颈都是出在数据库上面,至于程序语言快一点还是慢一点通常无关紧要,更何况这里的结果表明脚本语言有时候反而可能更快呢。
对于反射的测试,IronPython则是压倒性的战胜了C#。需要说明的一点是我在C#中反射生成对象使用的方法是ConstructorInfo.Invoke()。如果换成Activator.CreateInstance()的话,那么C#的时间将会缩减到230~250毫秒,不过即便这样仍然比IronPython落后一半左右。为什么使用反射时IronPython比C#快这么多呢?或许因为它运行的时候能够在内存中动态生成部分字节码,从而跳过反射环节,所以更快吧。
从这个实验的结果看,IronPython的性能可以说好到超出了我的预期。因为之前也看过其他一些相关的性能评测,比如说Ruby要比Java的运行速度慢30倍(这个比较已经有一段时间了,现在差距应该有所缩小),相比之下IronPython的性能简直可以用十分优异来形容了。当然脚本语言也有一个不足的地方,就是加载解释器的时候会带来几秒钟的固定开销,频繁修改程序的时候,这几秒钟还是有点让人难受的。好在以嵌入方式使用IronPython的时候,引擎只需要加载一次就够了,所以这个缺点大体上还是可以接受的。
【编辑推荐】