并发编程(九)使用多进程multiprocessing加速程序运行

并发编程专栏系列博客

并发编程(一)python并发编程简介

并发编程(二)怎样选择多线程多进程和多协程

并发编程(三)Python编程慢的罪魁祸首。全局解释器锁GIL

并发编程(四)如何使用多线程,使用多线程对爬虫程序进行修改及比较

并发编程(五)python实现生产者消费者模式多线程爬虫

并发编程(六)线程安全问题以及lock解决方案

并发编程(七)好用的线程池ThreadPoolExecutor

并发编程(八)在web服务中使用线程池加速

并发编程(九)使用多进程multiprocessing加速程序运行

并发编程(十)在Flask服务中使用进程池加速

并发编程(十一)python异步IO实现并发编程

并发编程(十二)使用subprocess启动电脑任意程序(听歌、解压缩、自动下载等等)

 
 

为什么要使用多进程?

有了多线程threading,为什么还要使用多进程multiprocessing

  • 如果遇到CPU密集型计算,多线程反而会降低执行速度!

  • 虽然有全局解释器锁GIL,但是因为有IO的存在,多线程依然可以加速运行。

在这里插入图片描述

  • CPU密集型计算,线程的自动切换反而变成了负担,多线程甚至减慢了运行速度。

在这里插入图片描述

  • 为了解决上面这个问题。我们就引入了多进程。multiprocessing模块就是python为了解决GIL缺陷引入的一个模块,原理是用多进程在多CPU上并行执行。
多进程multiprocessing使用方法(对比多线程Threading)
# 多线程引入模块
from threading import Thread
# 多进程引入模块
from multiprocessing import Process

# 多线程的新建、启动、等待结束
t = Thread(target=func, args=(x,))
t.start()
t.join()
# 多进程的新建、启动、等待结束
p = Process(target=func, args=(x,))
p.start()
p.join()

# 多线程数据通信
import queue
q = queue.Queue()
q.put(item)
item = q.get()
# 多进程数据通信
from multiprocessing import Queue
q = Queue()
q.put(item)
item = q.get()

# 多线程加锁
from threading import Lock
lock = Lock()
with lock:
    # do someting
    pass
# 多进程加锁
from multiprocessing import Lock
lock = Lock()
with lock:
    # do someting
    pass

# 多线程池化技术
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor() as executor:
    # 方法一
    rsts = executor.map(func, item)
    
    # 方法二
    future = executor.submit(func, x)
    rst = future.result
    
# 多进程池化技术
from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor() as executor:
    # 方法一
    rsts = executor.map(func, item)
    
    # 方法二
    future = executor.submit(func, x)
    rst = future.result()

(如果有疑问,可以参考前面几个博客的内容,前面几个博客已经详细介绍了线程的使用。而进程和线程基本一致)

代码实战:单线程、多线程、多进程对比CPU密集计算速度

我们先来看结果,我这儿测试的是连续100次判断一个很大的数字是否是素数。可以看出多线程会比单线程还耗时多。而多进程就大大减少了耗时。

在这里插入图片描述

原码及结果:

# -*- coding: utf-8 -*-
# @Time    : 2021-03-22 16:00:12
# @Author  : wlq
# @FileName: process_test.py
# @Email   :[email protected]
import math
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 需要判断列表,下面数字判断100次
PRIMES = [112272535095293] * 100


# 判断是否是素数
def is_prime(n):
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False
    sqrt_n = int(math.floor(math.sqrt(n)))

    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True


def single_thread():
    for x in PRIMES:
        is_prime(x)


def multi_thread():
    with ThreadPoolExecutor() as pool:
        pool.map(is_prime, PRIMES)


def multi_process():
    with ProcessPoolExecutor() as pool:
        pool.map(is_prime, PRIMES)


if __name__ == '__main__':
    start_time = time.time()
    single_thread()
    end_time = time.time()
    print("single_thread cost:", end_time - start_time)

    start_time = time.time()
    multi_thread()
    end_time = time.time()
    print("multi_thread cost:", end_time - start_time)

    start_time = time.time()
    multi_process()
    end_time = time.time()
    print("multi_process cost:", end_time - start_time)

    
'''
output:
single_thread cost: 63.33259177207947
multi_thread cost: 63.582000970840454
multi_process cost: 17.35455083847046
'''

通过代码结果,可以看出多进程在处理CPU密集型计算时会节省很多时间。反而,多线程处理CPU密集型计算会增加耗时。

猜你喜欢

转载自blog.csdn.net/qq_42546127/article/details/115133942
今日推荐