python3下multiprocessing、threading和gevent性能对比----暨进程池、线程池和协程池性能对比

 
  • 30004

目前计算机程序一般会遇到两类I/O:硬盘I/O和网络I/O。我就针对网络I/O的场景分析下python3下进程、线程、协程效率的对比。进程采用multiprocessing.Pool进程池,线程是自己封装的进程池,协程采用gevent的库。用python3自带的urlllib.request和开源的requests做对比。代码如下:

  1. import urllib.request
  2. import requests
  3. import time
  4. import multiprocessing
  5. import threading
  6. import queue
  7. def startTimer():
  8. return time.time()
  9. def ticT(startTime):
  10. useTime = time.time() - startTime
  11. return round(useTime, 3)
  12. #def tic(startTime, name):
  13. #    useTime = time.time() - startTime
  14. #    print('[%s] use time: %1.3f' % (name, useTime))
  15. def download_urllib(url):
  16. req = urllib.request.Request(url,
  17. headers={'user-agent': 'Mozilla/5.0'})
  18. res = urllib.request.urlopen(req)
  19. data = res.read()
  20. try:
  21. data = data.decode('gbk')
  22. except UnicodeDecodeError:
  23. data = data.decode('utf8', 'ignore')
  24. return res.status, data
  25. def download_requests(url):
  26. req = requests.get(url,
  27. headers={'user-agent': 'Mozilla/5.0'})
  28. return req.status_code, req.text
  29. class threadPoolManager:
  30. def __init__(self,urls, workNum=10000,threadNum=20):
  31. self.workQueue=queue.Queue()
  32. self.threadPool=[]
  33. self.__initWorkQueue(urls)
  34. self.__initThreadPool(threadNum)
  35. def __initWorkQueue(self,urls):
  36. for i in urls:
  37. self.workQueue.put((download_requests,i))
  38. def __initThreadPool(self,threadNum):
  39. for i in range(threadNum):
  40. self.threadPool.append(work(self.workQueue))
  41. def waitAllComplete(self):
  42. for i in self.threadPool:
  43. if i.isAlive():
  44. i.join()
  45. class work(threading.Thread):
  46. def __init__(self,workQueue):
  47. threading.Thread.__init__(self)
  48. self.workQueue=workQueue
  49. self.start()
  50. def run(self):
  51. while True:
  52. if self.workQueue.qsize():
  53. do,args=self.workQueue.get(block=False)
  54. do(args)
  55. self.workQueue.task_done()
  56. else:
  57. break
  58. urls = ['http://www.ustchacker.com'] * 10
  59. urllibL = []
  60. requestsL = []
  61. multiPool = []
  62. threadPool = []
  63. N = 20
  64. PoolNum = 100
  65. for i in range(N):
  66. print('start %d try' % i)
  67. urllibT = startTimer()
  68. jobs = [download_urllib(url) for url in urls]
  69. #for status, data in jobs:
  70. #    print(status, data[:10])
  71. #tic(urllibT, 'urllib.request')
  72. urllibL.append(ticT(urllibT))
  73. print('1')
  74. requestsT = startTimer()
  75. jobs = [download_requests(url) for url in urls]
  76. #for status, data in jobs:
  77. #    print(status, data[:10])
  78. #tic(requestsT, 'requests')
  79. requestsL.append(ticT(requestsT))
  80. print('2')
  81. requestsT = startTimer()
  82. pool = multiprocessing.Pool(PoolNum)
  83. data = pool.map(download_requests, urls)
  84. pool.close()
  85. pool.join()
  86. multiPool.append(ticT(requestsT))
  87. print('3')
  88. requestsT = startTimer()
  89. pool = threadPoolManager(urls, threadNum=PoolNum)
  90. pool.waitAllComplete()
  91. threadPool.append(ticT(requestsT))
  92. print('4')
  93. import matplotlib.pyplot as plt
  94. x = list(range(1, N+1))
  95. plt.plot(x, urllibL, label='urllib')
  96. plt.plot(x, requestsL, label='requests')
  97. plt.plot(x, multiPool, label='requests MultiPool')
  98. plt.plot(x, threadPool, label='requests threadPool')
  99. plt.xlabel('test number')
  100. plt.ylabel('time(s)')
  101. plt.legend()
  102. plt.show()

运行结果如下:

从上图可以看出,python3自带的urllib.request效率还是不如开源的requests,multiprocessing进程池效率明显提升,但还低于自己封装的线程池,有一部分原因是创建、调度进程的开销比创建线程高(测试程序中我把创建的代价也包括在里面)。

下面是gevent的测试代码:

  1. import urllib.request
  2. import requests
  3. import time
  4. import gevent.pool
  5. import gevent.monkey
  6. gevent.monkey.patch_all()
  7. def startTimer():
  8. return time.time()
  9. def ticT(startTime):
  10. useTime = time.time() - startTime
  11. return round(useTime, 3)
  12. #def tic(startTime, name):
  13. #    useTime = time.time() - startTime
  14. #    print('[%s] use time: %1.3f' % (name, useTime))
  15. def download_urllib(url):
  16. req = urllib.request.Request(url,
  17. headers={'user-agent': 'Mozilla/5.0'})
  18. res = urllib.request.urlopen(req)
  19. data = res.read()
  20. try:
  21. data = data.decode('gbk')
  22. except UnicodeDecodeError:
  23. data = data.decode('utf8', 'ignore')
  24. return res.status, data
  25. def download_requests(url):
  26. req = requests.get(url,
  27. headers={'user-agent': 'Mozilla/5.0'})
  28. return req.status_code, req.text
  29. urls = ['http://www.ustchacker.com'] * 10
  30. urllibL = []
  31. requestsL = []
  32. reqPool = []
  33. reqSpawn = []
  34. N = 20
  35. PoolNum = 100
  36. for i in range(N):
  37. print('start %d try' % i)
  38. urllibT = startTimer()
  39. jobs = [download_urllib(url) for url in urls]
  40. #for status, data in jobs:
  41. #    print(status, data[:10])
  42. #tic(urllibT, 'urllib.request')
  43. urllibL.append(ticT(urllibT))
  44. print('1')
  45. requestsT = startTimer()
  46. jobs = [download_requests(url) for url in urls]
  47. #for status, data in jobs:
  48. #    print(status, data[:10])
  49. #tic(requestsT, 'requests')
  50. requestsL.append(ticT(requestsT))
  51. print('2')
  52. requestsT = startTimer()
  53. pool = gevent.pool.Pool(PoolNum)
  54. data = pool.map(download_requests, urls)
  55. #for status, text in data:
  56. #    print(status, text[:10])
  57. #tic(requestsT, 'requests with gevent.pool')
  58. reqPool.append(ticT(requestsT))
  59. print('3')
  60. requestsT = startTimer()
  61. jobs = [gevent.spawn(download_requests, url) for url in urls]
  62. gevent.joinall(jobs)
  63. #for i in jobs:
  64. #    print(i.value[0], i.value[1][:10])
  65. #tic(requestsT, 'requests with gevent.spawn')
  66. reqSpawn.append(ticT(requestsT))
  67. print('4')
  68. import matplotlib.pyplot as plt
  69. x = list(range(1, N+1))
  70. plt.plot(x, urllibL, label='urllib')
  71. plt.plot(x, requestsL, label='requests')
  72. plt.plot(x, reqPool, label='requests geventPool')
  73. plt.plot(x, reqSpawn, label='requests Spawn')
  74. plt.xlabel('test number')
  75. plt.ylabel('time(s)')
  76. plt.legend()
  77. plt.show()

运行结果如下:

从上图可以看到,对于I/O密集型任务,gevent还是能对性能做很大提升的,由于协程的创建、调度开销都比线程小的多,所以可以看到不论使用gevent的Spawn模式还是Pool模式,性能差距不大。

因为在gevent中需要使用monkey补丁,会提高gevent的性能,但会影响multiprocessing的运行,如果要同时使用,需要如下代码:

  1. gevent.monkey.patch_all(thread=False, socket=False, select=False)

可是这样就不能充分发挥gevent的优势,所以不能把multiprocessing Pool、threading Pool、gevent Pool在一个程序中对比。不过比较两图可以得出结论,线程池和gevent的性能最优的,其次是进程池。附带得出个结论,requests库比urllib.request库性能要好一些哈:-)

转载请注明:转自http://blog.csdn.net/littlethunder/article/details/40983031

python3下multiprocessing、threading和gevent性能对比----暨进程池、线程池和协程池性能对比的更多相关文章

  1. 线程队列 concurrent 协程 greenlet gevent

    死锁问题 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...

  2. based on Greenlets (via Eventlet and Gevent) fork 孙子worker 比较 gevent不是异步 协程原理 占位符 placeholder (Future, Promise, Deferred) 循环引擎 greenlet 没有显式调度的微线程,换言之 协程

    gevent GitHub - gevent/gevent: Coroutine-based concurrency library for Python https://github.com/gev ...

  3. python 并发编程 基于gevent模块 协程池 实现并发的套接字通信

    基于协程池 实现并发的套接字通信 客户端: from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(('12 ...

  4. python3 - 多线程和协程速率测试对比

    多线程和协程都属于IO密集型,我通过以下用例测试多线程和协程的实际速率对比. 实例:通过socket客户端以多线程并发模式请求不同服务器端(这里服务器端分2种写法:第一种服务器通过协程实现,第二种服务 ...

  5. Swoole 同步模式与协程模式的对比

    在现代化 PHP 高级开发中,Swoole 为 PHP 带来了更多可能,如:常驻内存.协程,关于传统的 Apache/FPM 模式与常驻内存模式(同步)的巨大差异,之前我做过测试,大家能直观的感受到性 ...

  6. python采用 多进程/多线程/协程 写爬虫以及性能对比,牛逼的分分钟就将一个网站爬下来!

    首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务.一个CPU,在一个时间切片里只能运行一个程序. 从操作系统的角度: 进程和线程,都 ...

  7. 第十天 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)

    1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...

  8. 基础10 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)

    1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...

  9. Cpython解释器下实现并发编程——多进程、多线程、协程、IO模型

    一.背景知识 进程即正在执行的一个过程.进程是对正在运行的程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有内容都 ...

随机推荐

  1. mysql数据库问题———登录进去无法操作显示You must reset your password using ALTER USER statement before executing this statement

    linux操作mysql数据库,可以登陆进去,但是操作所有命令都显示You must reset your password using ALTER USER statement before exe ...

  2. 初次尝试python爬虫,爬取小说网站的小说。

    本次是小阿鹏,第一次通过python爬虫去爬一个小说网站的小说. 下面直接上菜. 1.首先我需要导入相应的包,这里我采用了第三方模块的架包,requests.requests是python实现的简单易 ...

  3. 环境变量和Path环境变量

    环境变量 百度百科下的定义 一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等. 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所 ...

  4. js日期格式验证

    js日期格式验证 <input type="text" maxLength='10' onkeyup='checkDate(this.value,jQuery(this)); ...

  5. HTML回顾之表格

    HTML表格 由什么组成? 表格由<table>标签来定义.每个表格有若干行(<tr>标签来定义),每行被分割成若干单元格(<td>标签来定义). td值表格数据, ...

  6. 工具使用——IDEA常用的几种插件

    Rainbow Brackets:彩虹颜色的括号 Maven Helper :分析依赖冲突插件 Grep Console:显示不同日志级别不同颜色 Mybatis Log Plugin:直接将Myba ...

  7. 关于Mysql5.6 Failed to open file error2的记录

    今天在执行mysql命令行下的\.命令时,它总说Failed to open file “...........”error2 找了半天原因,最后发现是百度云在往那个文件夹里下载东西,所以访问文件的时 ...

  8. 202-基于TI DSP TMS320C6678、Xilinx K7 FPGA XC7K325T的高速数据处理核心板

    该DSP+FPGA高速信号采集处理板由我公司自主研发,包含一片TI DSP TMS320C6678和一片Xilinx FPGA K7 XC72K325T-1ffg900.包含1个千兆网口,1个FMC ...

  9. Codeforces Round #430 (Div. 2) - D

    题目链接:http://codeforces.com/contest/842/problem/D 题意:定义Mex为一个序列中最小的未出现的正整数,给定一个长度为n的序列,然后有m个询问,每个询问给定 ...

  10. tf中的meta和pb

    https://www.jianshu.com/p/af2b694eae61 简单来说,pb文件是个推理的图,meta更复杂,不能用来部署