python几种并发实现方案的性能比较_第1页
python几种并发实现方案的性能比较_第2页
python几种并发实现方案的性能比较_第3页
python几种并发实现方案的性能比较_第4页
python几种并发实现方案的性能比较_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、转自:1 .刖日偶然看至UErlangvs.Stacklesspython:afirstbenchmark,对Erlang和StacklessPython的并发处理性能进展了实验比较,根本结论认为二者有比较相近的性能。我看完产生的问题是,StacklessPython与Python的其他并发实现机制性能又会有多大区别呢,比方线程和进程。因此我采用与这篇文章一样的方法来对StacklessPython、普通Python的thread模块、普通Python的threading模块、普通Python的processing模块这四种并发实现方案进展了性能实验,并将实验过程和根本结果记录在这里。后来看到

2、了基于greenlet实现的高性能网络框架Eventlet,因此更新了实验方案,将greenlet也参加了比较,虽然greenlet并非是一种真正意义上的并发处理,而是在单个线程下对程序块进展切换轮流执行。(EditSectionJ)2 .实验方案实验方案与Erlangvs.Stacklesspython:afirstbenchmark是一样的,用每种|方案分别给出如下问题的实现,记录完成整个处理过程的总时间来作为评判性能的根据:1 .由n个节点组成一个环状网络,在上面传送共m个消息。2 .将每个消息共m个,逐个发送给1号节点。3 .第1到n-1号节点在接收到消息后,都转发给下一号节点。4 .

3、第n号节点每次收到消息后,不再继续转发。5 .当m个消息都从1号逐个到达第n号节点时,认为全部处理完毕。(EditSectionJ)硬件平台MacbookPro3,1上的Vmware虚拟机中,注意这里给虚拟机只启用了cpu的单个核心:?原始Cpu:Core2Duo,2.4GHz,2核心,4MBL2缓存,总线速度800MHz?分配给虚拟机的内存:796M单个CPU,还能比较并发吗?(EditSectionJ)软件平台Vmware下的Debianetch:?原始Python:Debian发行版自带?Stackless3.1b3060516?processing-0.52-py2.4-linux-i

4、686.egg?原始Python下的greenlet实现:(EditSectionJ)3 .实验过程及结果各方案的实现代码见后文。实验时使用time指令记录每次运行的总时间,选用的都是不做任何输出的no_io实现Python的print指令还是挺耗资源的,假设不注释掉十有八九得影响测试结果,每次执行时设定n=300,m=10000Erlangvs.Stacklesspython:afirstbenchmark文章中认为n可以设置为300,m那么可以取10000到90000之间的数值分别进展测试。(EditSectionJ)StacklessPython的实验结果realusersys即使将m扩

5、大到30000,实验结果仍然很突出:realusersys(EditSectionJ)使用thread模块的实验结果realusersys(EditSectionJ)使用threading模块配合Queue模块的实验结果不太稳定,有时候这样:realusersys也有时这样:realusersys(EditSectionJ)使用processing模块配合Queue模块的实验结果realusersys(EditSectionJ)greenlet模块的实验结果realusersys(EditSectionJ)eventlet模块的实验结果注意!eventlet的这个实验结果是后来增补的,硬件平台

6、没变,但是是直接在OSX自带Python2.5环境下执行出来的,同时系统中还有Firefox等很多程序也在争夺系统资源。因此只能作为大致参考,不能与其他几组数据作直接比照。其中eventlet的版本是(EditSectionJ)4 .结论与分析(EditSectionJ)StacklessPython毫无疑问,StacklessPython几乎有匪夷所思的并发性能,比其他方案快上几十倍,而且借助StacklessPython提供的channel机制,实现也相当简单。也许这个结果向我们部分提醒了沈仙人基于StacklessPython实现的Eurasia3可以提供相当于c语言效果的恐惧并发性能的

7、原因。(EditSectionJ)Python线程从道理上来讲,thread模块似乎应该和threading提供根本一样的性能,毕竟threading只是对thread的一种封装嘛,后台机制应该是一致的。或许threading由于本身类实例维护方面的开销,应该会比直接用thread慢一点。从实验结果来看,二者性能也确实差不多。只是不大明白为何threading方案的测试结果不是很稳定,即使对其他方案的测试运行屡次,误差也不会像threading这么飘。从代码实现体验来说,用threading配合Queue比直接用thread实在是轻松太多了,并且出错的时机也要少很多。(EditSectionJ

8、)Python进程processing模块给出的进程方案大致比thread线程要慢一倍,并且这是在我特意调整虚拟机给它预备了足够空闲内存、防止使用交换分区的情况下获得的特意分给虚拟机700多M内存就是为了这个。而其他方案仅仅占用数M内存,完全无需特意调大可用内存总量。当然,假设给虚拟机多启用几个核心的话,processing也许会占上点廉价,毕竟目前thread模块是不能有效利用多cpu资源的经实验,StacklessPython在开启双核的情况下表现的性能和单核是一样的,说明也是不能有效利用多cpu。因此一种比较合理的做法是根据cpu的数量,启用少量几个进程,而在进程内部再开启线程进展实际业

9、务处理,这也是目前Python社区推荐的有效利用多cpu资源的方法。好在processing配合其自身提供的Queue模块,编程体验还是比较轻松的。(EditSectionJ)greenlet超轻M级方案基于greenlet的实现那么性能仅次于StacklessPython,大致比StacklessPython慢一倍,比其他方案快接近一个数量级。其实greenlet不是一种真正的并发机制,而是在同一线程内,在不同函数的执行代码块之间切换,施行你运行一会、我运行一会,并且在进展切换时必须指定何时切换以及切换到哪。greenlet的接口是比较简单易用的,但是使用greenlet时的考虑方式与其他并

10、发方案存在一定区别。线程/进程模型在大逻辑上通常从并发角度开始考虑,把可以并行处理的并且值得并行处理的任务别离出来,在不同的线程/进程下运行,然后考虑别离过程可能造成哪些互斥、冲突问题,将互斥的资源加锁保护来保证并发处理的正确性。greenlet那么是要求从防止阻塞的角度来进展开发,当出现阻塞时,就显式切换到另一段没有被阻塞的代码段执行,直到原先的阻塞状况消失以后,再人工切换回原来的代码段继续处理。因此,greenlet本质是一种合理安排了的用行,实验中greenlet方案可以得到比较好的性能表现,主要也是因为通过合理的代码执行流程切换,完全防止了死锁和阻塞等情况执行带屏幕输出的我们会看到脚本

11、总是一个一个地处理消息,把一个消息在环上从头传到尾之后,再开始处理下一个消息。因为greenlet本质是串行,因此在没有进展显式切换时,代码的其他部分是无法被执行到的,假设要防止代码长时间占用运算资源造成程序假死,那么还是要将greenlet与线程/进程机制结合使用每个线程、进程下都可以建立多个greenlet,但是跨线程/进程时greenlet之间无法切换或通讯。Stackless那么比较特别,对很多资源从底层进展了并发改造,并且提供了channel等更适宜并发的通讯机制实现,使得资源互斥冲突的可能性大大减小,并发性能自然得以进步。粗糙来讲,greenlet是阻塞了我就先干点儿别的,但是程序

12、员得明确告诉greenlet能先干点儿啥以及什么时候回来;Stackless那么是东西我已经改造好了,你只要用我的东西,并发冲突就不用操心,只管放心大胆地并发好了。greenlet应该是学习了Stackless的上下文切换机制,但是对底层资源没有进展适宜并发的改造。并且实际上greenlet也没有必要改造底层资源的并发性,因为它本质是串行的单线程,不与其他并发模型混合使用的话是无法造成对资源的并发访问的。(EditSectionJ)greenlet封装后的eventlet方案eventlet是基于greenlet实现的面向网络应用的并发处理框架,提供线程池、队列等与其他Python线程、进程模

13、型非常相似的api,并且提供了对Python发行版自带库及其他模块的超轻量并发适应性调整方法,比直接使用greenlet要方便得多。并且这个解决方案源自著名虚拟现实游戏第二人生,可以说是久经考验的新兴并发处理模型。其根本原理是调整Python的socket调用,当发生阻塞时那么切换到其他greenlet执行,这样来保证资源的有效利用。需要注意的是:?eventlet提供的函数只能对Python代码中的socket调用进展处理,而不能对模块的C语言部分的socket调用进展修改。对后者这类模块,仍然需要把调用模块的代码封装在Python标准线程调用中,之后利用eventlet提供的适配器实现ev

14、entlet与标准线程之间的协作。?再有,虽然eventlet把api封装成了非常类似标准线程库的形式,但两者的实际并发执行流程仍然有明显区别。在没有出现I/O阻塞时,除非显式声明,否那么当前正在执行的eventlet永远不会把cpu交给其他的eventlet,而标准线程那么是无论是否出现阻塞,总是由所有线程一起争夺运行资源。所有eventlet对I/O阻塞无关的大运算量耗时操作根本没有什么帮助。在性能测试结果方面,eventlet消耗的运行时间大致是greenlet方案的3到5倍,而Python标准线程模型的thread方式消耗的运行时间大致是eventlet测试代码的8到10倍。其中前者可

15、能是因为我们在eventlet的测试代码中,使用队列机制来完成所有的消息传递,而队列上的访问互斥保护可能额外消耗了一些运算资源。总体而言,eventlet模型的并发性能虽然比StacklessPython和直接使用greenlet有一定差距,但仍然比标准线程模型有大约一个数量级的优势,这也就不奇怪近期很多强调并发性能的网络效劳器实现采取eventlet、线程、进程三者组合使用的实现方案。(EditSectionJ)5 .实验代码实验代码下载:?版本3下载:增加了eventlet方案的实验代码。?版本2下载:增加了greenlet方案的实验代码。?版本1下载:包括StacklessPython、

16、thread、threading、processing四种方案的实验代码。为方便阅读,将实验中用到的几个脚本的代码粘贴如下,其中StacklessPython方案的代码实现直接取自Erlangvs.Stacklesspython:afirstbenchmark:(EditSectionJ)1. #!/Library/Frameworks/2. #encoding:utf-83. importsys4. importstacklessasSL5.6. defrun_benchmark(n,m):7. stackless3.1b3here(N=%d,M=%d)!n"%(n,m)8. fi

17、rstP=cin=()9. forsinxrange(1,n):10. seqn=s11. cout=()12. #print("*>s=%d"%(seqn,)13. t=(loop)(seqn,cin,cout)14. cin=cout15. else:16. seqn=s+117. #print("$>s=%d"%(seqn,)18. t=(mloop)(seqn,cin)19. forrinxrange(m-1,-1,-1):20. #print("+sendingMsg#%d"%r)21. (r)22. ()23.

18、 defloop(s,cin,cout):24. whileTrue:25. r=()26. (r)27. ifr>0:28. #print(":Proc:<%s>,Seq#:%s,Msg#:%s."(pid(),s,r)29. pass30. else:31. #print("*Proc:<%s>,Seq#:%s,Msg#:terminate!"%(pid(),s)32. break33. defmloop(s,cin):34. whileTrue:35. r=()36. ifr>0:37. #print("

19、;>Proc:<%s>,Seq#:%s,Msg#:%s."(pid(),s,r)38. pass39. else:40. #print("Proc:<%s>,Seq#:%s,ringterminated."%(pid(),s)41. break42.43. defpid():returnrepr().split()-12:-144.45. if_name_='_main_'46. run_benchmark(int(sys.argv1),int(sys.argv2)GetCode(EditSectionJ)1. #!/

20、Library/Frameworks/2. #encoding:utf-83. importsys,time4. importthread5.6. SLEEP_TIME=7.8. defrun_benchmark(n,m):9. stackless3.1b3here(N=%d,M=%d)!n"%(n,m)10. locks=thread.allocate_lock()foriinxrange(n)11. firstP=cin=12. cin_lock_id=013. forsinxrange(1,n):14. seqn=s15. cout=16. cout_lock_id=s17.

21、#print("*>s=%d"%(seqn,)18. thread.start_new_thread(loop,(seqn,locks,cin,cin_lock_id,cout,cout_lock_id)19. cin=cout20. cin_lock_id=cout_lock_id21. else:22. seqn=s+123. #print("$>s=%d"%(seqn,)24. thread.start_new_thread(mloop,(seqn,locks,cin,cin_lock_id)25. forrinxrange(m-1,-

22、1,-1):5.66.#print("+sendingMsg#%d"%r)lock=locks0()(r)()time.sleep(SLEEP_TIME)try:whileTrue:time.sleep(SLEEP_TIME)except:passdefloop(s,locks,cin,cin_lock_id,cout,cout_lock_i

23、d):whileTrue:lock=lockscin_lock_id()一一iflen(cin)>0:r=cin.pop(0)()else:()time.sleep(SLEEP_TIME)continuelock=lockscout_lock_id()一一(r)()ifr>0:# print(":Proc:<%s>,Seq#:%s,Msg#:%s."%(pid(),s,r)passelse:# print("*Proc:<%s>,Seq#:%s,Msg#:terminate!"%(pid(),s)breakdefmlo

24、op(s,locks,cin,cin_lock_id):whileTrue:lock=lockscin_lock_id()一一iflen(cin)>0:r=cin.pop(0)()else:()67. time.sleep(SLEEP_TIME)68. continue69. ifr>0:70. #print(">Proc:<%s>,Seq#:%s,Msg#:%s."%(pid(),s,r)71. pass72. else:73. #print("Proc:<%s>,Seq#:%s,ringterminated."

25、;%(pid(),s)74. break75. errupt_main()76.77. defpid():returnthread.get_ident()78.79. if_name_='_main_'80. run_benchmark(int(sys.argv1),int(sys.argv2)GetCode(EditSectionJ)1. #!/Library/Frameworks/2. #encoding:utf-83. importsys4. importthreading,Queue5.6. defrun_benchmark(n,m):7. stac

26、kless3.1b3here(N=%d,M=%d)!n"%(n,m)8. firstP=cin=Queue.Queue()9. forsinxrange(1,n):10. seqn=s11. cout=Queue.Queue()12. #print("*>s=%d"%(seqn,)13. t=Loop(seqn,cin,cout)14. (False)15. ()16. cin=cout17. else:18. seqn=s+119. #print("$>s=%d"%(seqn,)20. t=MLoop(seqn,cin)21. (

27、False)7.()forrinxrange(m-1,-1,-1):#print("+sendingMsg#%d"%r)(r)classLoop(threading.Thread):def_init_(self,s,cin,cout):threading.Thread._init_(self)self.cin=cinself.cout=coutself.s=sdefrun(self):whileTrue:r=self()self(r)ifr>0:#print(":Pr

28、oc:<%s>,Seq#:%s,Msg#:%s."%(pid(),r)38. pass39. else:%s, Msg#:40. #print("*Proc:<%s>,Seq#:terminate!"%(pid(),)41. break1.classMLoop(threading.Thread):def_init_(self,s,cin):threading.Thread._init_(self)self.cin=cinself.s=sdefrun(self):whileTrue:r=

29、self()ifr>0:#print(">Proc:<%s>,Seq#:%s,Msg#:%s."%(pid(),r)52. pass53. else:54. #print("Proc:<%s>,Seq#:%s,ringterminated."%(pid(),)55. break56.57. defpid():returnthreading.currentThread()58.59. if_name_='_main_':60. run_benchmark(int(sys.argv1),int(sys.ar

30、gv2)(EditSectionJ)1.#!/Library/Frameworks/..8.29.30.#encoding:utf-8importsysimportprocessing,Queuedefrun_benchmark(n,m):stackless3.1b3here(N=%d,M=%d)!n"%(n,m)firstP=cin=processing.forsinxrange(1,n):seqn=scout=processing.Queue(

31、)Queue()#print("*>s=%d"%(seqn,)p=(target=loop,args=seqn,cin,cout)()cin=coutelse:seqn=s+#print("$>s=%d"%(seqn,)p=(target=mloop,args=seqn,cin)()forrinxrange(m-1,-1,-1):#print("+sendingMsg#%d"%r)(r)GetCode()defloop(s,cin,cout):whiler=()(r)ifTrue:r>0:#print(":

32、Proc:<%s>,Seq#:%s,4.Msg#:%s."%(pid(),s,r)passelse:#print("*Proc:<%s>,Seq#:%s,Msg#:terminate!"%(pid(),s)break35.defmloop(s,cin):36.whileTrue:37. r=()38. ifr>0:39. #print(">Proc:<%s>,Seq#:%s,Msg#:%s."(pid(),s,r)40. pass41. else:42. #print(&quo

33、t;Proc:<%s>,Seq#:%s,ringterminated."%(pid(),s)43. break44.45. defpid():return()46.47. if_name_='_main_'48. run_benchmark(int(sys.argv1),int(sys.argv2)GetCode(EditSectionJ)1. #!/Library/Frameworks/2. #encoding:utf-83. importsys4. fromimportgreenlet5.6. defrun_benchmark(n,m):7. stac

34、kless3.1b3here(N=%d,M=%d)!n"%(n,m)8. glets=()9. forsinxrange(1,n):10. seqn=s11. (greenlet(loop)12. #print("*>s=%d"%(seqn,)13. else:14. seqn=s+115. (greenlet(mloop)16. #print("$>s=%d"%(seqn,)17. glets-1.switch(seqn,glets)18. forrinxrange(m-1,-1,-1):19. #print("+sen

35、dingMsg#%d"%r)20. glets1.switch(r)21. defloop(s,glets):22. previous=gletss-123. next=gletss+124.if s> 1:25.r=(s-1, glets)26.else :27.r=()28.whileTrue :29.ifr > 0:30.# print(":Proc:(pid("loop", s), s,r)31.pass32.else :<%s>, Seq#: %s, Msg#: %s.33. #print("*Proc:<

36、;%s>,Seq#:%s,Msg#:terminate!"%(pid("loop",s),s)34. break35. (r)36. r=()37. (r)38. defmloop(s,glets):1Proc: <%s>, Seq#: %s, Msg#: %s.39. previous=gletss-40. r=(s-1,glets)41. whileTrue:42. ifr>0:43. #print(">(pid("mloop",s),s,r)44. pass45. else46. #print("Proc:<%s>,Seq#:%s,ringterminated."%(pid("mloop",s),s)47. brea

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论