Python 多进程、多线程效率比较

Python 界有条不成文的准则: 计算密集型任务适合多进程,IO 密集型任务适合多线程。本篇来作个比较。

通常来说多线程相对于多进程有优势,因为创建一个进程开销比较大,然而因为在 python 中有 GIL 这把大锁的存在,导致执行计算密集型任务时多线程实际只能是单线程。而且由于线程之间切换的开销导致多线程往往比实际的单线程还要慢,所以在 python 中计算密集型任务通常使用多进程,因为各个进程有各自独立的 GIL,互不干扰。

而在 IO 密集型任务中,CPU 时常处于等待状态,操作系统需要频繁与外界环境进行交互,如读写文件,在网络间通信等。在这期间 GIL 会被释放,因而就可以使用真正的多线程。

以上是理论,下面做一个简单的模拟测试: 大量计算用 math.sin() + math.cos() 来代替,IO 密集型用 time.sleep() 来模拟。 在 Python 中有多种方式可以实现多进程和多线程,这里一并纳入看看是否有效率差异:

  1. 多进程: joblib.multiprocessing, multiprocessing.Pool, multiprocessing.apply_async, concurrent.futures.ProcessPoolExecutor
  2. 多线程: joblib.threading, threading.Thread, concurrent.futures.ThreadPoolExecutor
from multiprocessing import Pool
from threading import Thread
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os, math
from joblib import Parallel, delayed, parallel_backend

def f_IO(a):  # IO 密集型
    time.sleep(5)

def f_compute(a):  # 计算密集型
    for _ in range(int(1e7)):
        math.sin(40) + math.cos(40)
    return

def normal(sub_f):
    for i in range(6):
        sub_f(i)
    return

def joblib_process(sub_f):
    with parallel_backend("multiprocessing", n_jobs=6):
        res = Parallel()(delayed(sub_f)(j) for j in range(6))
    return

def joblib_thread(sub_f):
    with parallel_backend(‘threading‘, n_jobs=6):
        res = Parallel()(delayed(sub_f)(j) for j in range(6))
    return

def mp(sub_f):
    with Pool(processes=6) as p:
        res = p.map(sub_f, list(range(6)))
    return

def asy(sub_f):
    with Pool(processes=6) as p:
        result = []
        for j in range(6):
            a = p.apply_async(sub_f, args=(j,))
            result.append(a)
        res = [j.get() for j in result]

def thread(sub_f):
    threads = []
    for j in range(6):
        t = Thread(target=sub_f, args=(j,))
        threads.append(t)
        t.start()
    for t in threads:
        t.join()

def thread_pool(sub_f):
    with ThreadPoolExecutor(max_workers=6) as executor:
        res = [executor.submit(sub_f, j) for j in range(6)]

def process_pool(sub_f):
    with ProcessPoolExecutor(max_workers=6) as executor:
        res = executor.map(sub_f, list(range(6)))

def showtime(f, sub_f, name):
    start_time = time.time()
    f(sub_f)
    print("{} time: {:.4f}s".format(name, time.time() - start_time))

def main(sub_f):
    showtime(normal, sub_f, "normal")
    print()
    print("------ 多进程 ------")
    showtime(joblib_process, sub_f, "joblib multiprocess")
    showtime(mp, sub_f, "pool")
    showtime(asy, sub_f, "async")
    showtime(process_pool, sub_f, "process_pool")
    print()
    print("----- 多线程 -----")
    showtime(joblib_thread, sub_f, "joblib thread")
    showtime(thread, sub_f, "thread")
    showtime(thread_pool, sub_f, "thread_pool")

if __name__ == "__main__":
    print("----- 计算密集型 -----")
    sub_f = f_compute
    main(sub_f)
    print()
    print("----- IO 密集型 -----")
    sub_f = f_IO
    main(sub_f)

结果:

----- 计算密集型 -----
normal time: 15.1212s

------ 多进程 ------
joblib multiprocess time: 8.2421s
pool time: 8.5439s
async time: 8.3229s
process_pool time: 8.1722s

----- 多线程 -----
joblib thread time: 21.5191s
thread time: 21.3865s
thread_pool time: 22.5104s

----- IO 密集型 -----
normal time: 30.0305s

------ 多进程 ------
joblib multiprocess time: 5.0345s
pool time: 5.0188s
async time: 5.0256s
process_pool time: 5.0263s

----- 多线程 -----
joblib thread time: 5.0142s
thread time: 5.0055s
thread_pool time: 5.0064s

上面每一方法都统一创建6个进程/线程,结果是计算密集型任务中速度:多进程 > 单进程/线程 > 多线程, IO 密集型任务速度: 多线程 > 多进程 > 单进程/线程。

/

原文地址:https://www.cnblogs.com/massquantity/p/10357898.html

时间: 2024-08-30 03:17:44

Python 多进程、多线程效率比较的相关文章

python 多进程/多线程/协程 同步异步

这篇主要是对概念的理解: 1.异步和多线程区别:二者不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段.异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情.实现异步可以采用多线程技术或则交给另外的进程来处理.多线程的好处,比较容易的实现了 异步切换的思想, 因为异步的程序很难写的.多线程本身程还是以同步完成,但是应该说比效率是比不上异步的. 而且多线很容易写, 相对效率也高. 2.异步和同步的区别:  在io等待的时候,同步不会切走,浪费了时间.异

Python 多进程 多线程数据共享

#!/usr/bin/env python # -*- coding:utf-8 -*- # author: Changhua Gong from multiprocessing import Process, Queue import os, time, random ''' 1. 我们平时from queue import Queue是线程对列,用于数据共享的,只能在线程之间进行使用: 2. from multiprocessing import Queue,是进程对列,用于进程间数据交换,

python多进程多线程的区别

进程与线程 进程 进程模块,multiprocessing  的 Process 进程的创建 变量 =  Process(target = 指定函数,args = (1,))指定函数参数 这样我们就创建了一个进程,target 无需加括号! 我们通过 变量.start() 调用某进程, 然后使用:变量.join()阻塞母进程, 让母进程等待子进程执行完毕.否则就母进程先执行了, 那样就达不到我们想要的结果了. 有的时候有可能串行比并行要快,并行来回切换有可能用的时间更长! 假设中间有停顿的话,比

(转)python多进程、多线程编程

1 概念梳理: 1.1 线程 1.1.1 什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令. 1.1.2 线程的工作方式 假设你正在读一本书,没有读完,你想休息一下,但是你想在回来时恢复到当时读的具体进度.有一个方法就是记下页数.行数与字数这三个数值,这

python下多线程是鸡肋,推荐使用多进程 代码示例

最近在看Python的多线程,经常我们会听到老手说:“python下多线程是鸡肋,推荐使用多进程!”,但是为什么这么说呢? 要知其然,更要知其所以然.所以有了下面的深入研究: 首先强调背景: 1.GIL是什么?GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定. 2.每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念.但并发和并行

Python 多进程多线编程模板

一.Python 多进程多线程原理介绍 1. Python 全局解释器锁GIL a) Python的全局解释器锁GIL是互斥锁,能够防止本机多个线程一次执行Python字节码:由于CPython的内存管理在线程级别是不安全的(内存泄露),所以这个全局解释器锁是必须的.每个Python进程只能申请使用一个GIL锁,因此Python的多线程虽然是并发的但不能并行处理.Python的解释器每次只能执行一个线程,待GIL锁释放后再执行下一个线程,这样线程轮流被执行. b) Python2.x里,GIL的

Python的多线程和多进程模块对比测试

本文主要对比测试Python的多线程和多进程模块在CPU类型和I/O的任务操作时的效率 一 测试CPU消耗类型任务 在一台多核CPU的服务器上执行多线程代码,理论上代码执行时会利用多余的CPU核心来提升性能.但是由于Python的GIL的存在,使用多线程来执行CPU繁重的任务,未必能得到性能提升.但是GIL又必不可少,因为在Python解释器中执行线程是不安全的,也就是说为了保证Python线程执行时的安全,Python提供了一个全局锁,同一时刻,只允许一个线程获得这个全解锁并执行. CPU消耗

Python多进程和多线程

多进程 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回. 想要在windows平台编写多进程,需要引入multiprocessing模块. from multiprocessing import Process import os def run_proc(name): print('child pid

Python的多线程threading和多进程multiprocessing

python中的多线程就是在一个进程中存在着多个线程,在线程中,所有的线程都是共享资源的,线程之间的数据通信很简单.但是python仅支持一个线程的运行,因为python中存在一个全局解释器锁GIL(global interpreter lock),正是这个锁能保证同一时刻只有一个线程在运行,所以多线程依旧像是单线程的运行. GIL无疑就是一把对多线程有影响的全局锁,解决它对多线程的影响,不单单是释放GIL这么简单.GIL使得对象模型都是可以并发访问.GIL全局解释器锁解决多线程之间数据完整性和

Python多进程和多线程是鸡肋嘛?【转】

GIL是什么 Python的代码执行由 Python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行.即每个CPU在任意时刻只有一个线程在解释器中运行.对 Python虚拟机访问的控制由全局解释锁GIL控制,正是这个锁来控制同一时刻只有一个线程能够运行.——在单核CPU下的多线程其实都只是并发,不是并行 . 并发与并行区别 并发:两个或多个事件在同一时间间隔发生,或者说交替做不同事件的能力,或者说不同的代码块交替执行.