python是如何实现进程池和线程池的_进程池、线程池效率测试

v2-120faf2d5201e53095b80395b5d269f2_1440w.jpg?source=172ae18b

之前我们分别对计算密集型和IO密集型任务,测试过多线程对运行效率的改进,下面我们依然分计算密集、文件读写、网络请求三个部分,测试使用线程池、进程池如何改进运行效率

首先导入库并定义三种任务的函数

import requests
from bs4 import BeautifulSoup
import time
import numpy as np
from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import Pool

# 计算从1加到50000000
def cal(a = None): # 参数a没用,只是为了和后面统一
    s = 0
    for i in range(50000000):
        s = s + i

# 5000000次写入文件
def file(a = None): # 参数a没用,只是为了和后面统一
    with open('try.txt', 'w') as f:
        for i in range(5000000):
            f.write('abcdn')

# 抓取豆瓣top250的10个网页
def gettitle(a):
    url = 'https://movie.douban.com/top250?start={}&filter='.format(a*25)
    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')
    lis = soup.find('ol', class_='grid_view').find_all('li')
    for li in lis:
        title = li.find('span', class_="title").text
        print(title)

下面定义线性计算、多线程、多进程的函数

# 分别将上面三个函数传入,计算10次,返回正常循环的运行总时间
def nothing(func):
    t = time.time()
    for i in range(10):
        func(i)
    duration = time.time() - t
    return duration

# 分别将上面三个函数传入,计算10次,返回使用多线程的运行总时间
def thread(func):
    t = time.time()
    pool = ThreadPool(4)
    pool.map(func, range(10))
    duration = time.time() - t
    return duration

# # 分别将上面三个函数传入,计算10次,返回使用多进程的运行总时间
def process(func):
    t = time.time()
    pool = Pool(4)
    pool.map(func, range(10))
    duration = time.time() - t
    return duration

下面定义计算运行时间的函数

def get_duration(curr, func):
    l = []
    for _ in range(5):
        l.append(curr(func))
    mean_duration = '%.2f' % np.mean(l)
    all_duration = ['%.2f' % i for i in l]
    return mean_duration, all_duration

下面运行代码计算时间

if __name__ == '__main__':
    # CPU密集任务对比
    print(get_duration(nothing, cal))
    print(get_duration(thread, cal))
    print(get_duration(process, cal))
    # 文件读写任务对比
    print(get_duration(nothing, file))
    print(get_duration(thread, file))
    print(get_duration(process, file))
    # 网络请求任务对比
    print(get_duration(nothing, gettitle))
    print(get_duration(thread, gettitle))
    print(get_duration(process, gettitle))

结果如下

------CPU密集型任务运行时间-------
线性运算
('39.98', ['39.57', '39.36', '40.53', '40.09', '40.35'])
多线程
('38.31', ['39.07', '37.96', '38.07', '38.31', '38.13'])
多进程
('27.43', ['27.58', '27.11', '27.82', '27.53', '27.11'])
------文件读写任务运行时间-------
线性运算
('54.11', ['53.54', '53.96', '54.46', '53.54', '55.03'])
多线程
('53.86', ['55.44', '54.12', '52.48', '53.17', '54.08'])
多进程
('34.98', ['35.14', '34.35', '35.27', '35.20', '34.94'])
------网络请求任务运行时间-------
线性运算
('4.77', ['4.74', '4.70', '4.77', '4.91', '4.72'])
多线程
('1.96', ['1.88', '2.09', '1.91', '2.04', '1.91'])
多进程
('3.79', ['3.55', '3.70', '3.50', '3.92', '4.30'])

分析如下

  • 首先,CPU密集型运算。多线程无法改善运行效率,多进程可以改善。因为多进程能够利用计算机的多核优势,调用了更多资源进行计算
  • 在进行CPU密集运算时,可以监测任务管理器,发现在线性运算和多线程时,CPU利用率连一半都不到;而在多进程时就跑满了所有的CPU
  • 注意一点:这里使用线程池(进程池)都只开了4个线程(进程),因为在我的计算机上,用4个进程可以最大化利用CPU的计算能力,开更多进程也无法在计算密集型任务运行上有更大的优势,反而会增加进程创建和切换的时间。
  • 其次,文件读写任务。上面结果显示只有多进程对运行效率有所改善。
  • 其实文件读写任务有时候多线程也是可以改善效率的,是在打开文件、读写文件比较慢的时候,而上面展示的可能因为文件比较小,读入内容比较少,所以耗费的时间基本在于操作频繁,还是CPU负载问题,所以多线程无法提高运行效率
  • 如果读写文件是与数据库连接,等待的时间就会长一些,这时多线程也能发挥更大的优势
  • 为了更好地展现多线程在文件读写方面的优势,我又进行了下面测试

file函数改为(即每次写入内容增多)

# 500次写入文件
def file(a = None): # 参数a没用,只是为了和后面统一
    for i in range(500):
        with open('try.txt', 'w') as f:
            f.write('abcd'*100000 + 'n')

运行结果如下

线性运算
('55.15', ['49.96', '55.75', '45.11', '52.16', '72.75'])
多线程
('26.57', ['26.67', '23.89', '25.48', '32.84', '23.94'])
多进程
('25.72', ['24.10', '25.82', '24.13', '28.03', '26.50'])

可以看出这种情况下,多线程对效率的改善程度和多进程差不多。

  • 再次,网络请求任务。上面结果显示多线程对这种任务的效率改善最为明显,多进程也有些许改善。
  • 因为网络请求任务最主要的时间消耗在于等待网页的回复,这时如果能同时等待多个网页的回复,就能极大提高运行效率,多线程在此可以完美发挥作用。
  • 最后注意一点,使用多进程时,创建进程时间开销非常大,所以上面代码只有通过提高函数运行时间来、才能展示多进程的优势。网络请求任务多进程没有改善很多的原因也正在于此。而创建多线程则轻松很多。
  • 结论:CPU密集任务一般用多进程提高运行效率,网络请求任务一般用多线程提高运行效率,文件读写看主要是CPU计算耗时还是等待耗时。

专栏信息

专栏主页:python编程

专栏目录:目录

版本说明:软件及包版本说明

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值