轻松实现Python中的多进程与多线程
citgpt 2024-09-09 02:15 12 浏览 0 评论
在文章开始之前先说一句,小编最近整理了一套Python学习教程,有需要的小伙伴,记得关注小编头条号,私信【学习】即可免费领取一套Python学习教程哦
今天我们来聊聊Python里面的多进程与多线程编程模式。
01 多线程工作
在开始讲今天的正文之前,先给大家介绍一个概念「多线程工作」,这个概念可能有的人听过,也可能有的人平常工作中就是这么做的。我再来给大家讲讲这个概念,所谓的「多线程工作」就是同时做好几件事情。
拿我个人工作中例子来说,当我用Sql跑数的时候,数据不可能一下子就导出来,我会在一个屏幕上显示Sql运行进度,在另一个屏幕上先做一会PPT,等Sql跑出来以后,我就又会迅速切换到处理刚刚导出来的数据。有的时候数据量很大,用Excel打开文件可能需要几分钟的时间,这个时候Excel是处于运行状态,我是没法在Excel上做别的事情,我会去微信上去处理别人的一些问题,当文件打开以后,我会迅速切换到Excel上继续下一步处理,当我输入一个公式以后,Excel可能又需要等待一会,这个时候我就可以再去做一些别的事情。
大家可以看到,我没有在等一件事情彻底做完以后再去做另一件事情,而是在不同事情之间迅速切换,这种工作方式就可以算是一种「多线程工作」。
「多线程工作」可以减少你等待的时间,大大提高你的工作效率。
02 多进程与多线程
了解了「多线程工作」以后,我们开始进入今天的正题,编程里面的多线程和多进程。在上面的例子中Sql跑数可以算是一个进程、做PPT也可以算是一个进程、Excel处理数据还是一个进程。
进程下面还有一个更小的单位就是线程,一个进程由若干个线程组成,Sql跑数这个进程可以由写Sql、运行Sql、导出数据这几个线程组成。同样,PPT制作这个进程可以由明确主题、选模板、列大纲、丰富页面这几个线程组成。
线程是程序执行的最小单位,一个进程可以由一个或多个线程组成,各个线程之间也是交叉执行。
这里需要注意的是,多进程/多线程并不能做到同时去做好几件事情,而是把不同的事情交叉着做,做一段时间任务a,然后强制停止,去做一会任务b,再停止,再去做任务c。之所以会觉得各个任务之间是同时进行的原因是是任务与任务之间切换速度足够快,这样看起来就像是多个任务同时在进行。
我们再来看两个概念:
并行:指在同一时刻,有多条指令在多个处理器上同时执行;并发:指在同一时刻,只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
多份工作有多个人同时在做时就是并行,当多份工作由一个人交替在做时就是并发。在计算机中也是同样的概念,计算机中CPU的核数就相当于人数,当计算机是单核多任务时就是并发;当计算机是多核且大于任务数时,就是并行。
目前电脑主流配置都是四核/八线程的,而实际工作的任务数大都大于四个,所以也是需要交替来执行具体任务的,也就是并发执行。
我电脑运行情况
上面就是关于多线程与多进程的一个简单通俗的理解,一些太官方的解释我就不在这里放了,大家感兴趣的可以去自行上网查。
03 多进程与多线程是如何提高效率的
假设做任务A需要1个小时、任务B需要1个小时、任务C需要一个小时,当我们每个任务做20分钟以后切换到另一个任务,这样做完三个任务需要的总时间是不会变的,不仅不会变,反而可能会增加,因为在不同任务之间切换是需要代价的,因为当你从一个任务切换到另一个任务时很有可能不记得刚刚做到哪里了,还需要花时间想一想。那既然是这样,我们为什么还要用多进程/多线程这种处理任务的方式呢?我在第一小节里面提过,「多线程工作」可以减少你等待的时间,大大提高你的工作效率。
是因为在实际工作中,有很多需要等待的地方,比如等待Excel打开,等待Sql跑出数据。多进程/多线程任务处理方式就是充分利用这些等待时间。让你的大脑,计算机的大脑(CPU)得到充分的利用。如果要是没有等待的时间,多进程/多线程的任务处理方式可能就不如单线程的了。
04 多进程与多线程是如何实现的
了解清楚了多进程与多线程是什么,以及是如何提高处理任务的效率的以后,我们进入到硬干货部分,那就是具体多进程/多线程如何实现“同时”处理多任务的。
实现多任务的方式主要有以下几种:
1、多进程模式
2、多线程模式
3、多进程+多线程
同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务1必须暂停等待任务2完成后才能继续执行,有时,任务3和任务4又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。
4.1多进程模式
多进程就是一次启动多个进程,每个进程只有一个线程,但多个进程可以一起执行多个任务。一般进程数默认是电脑CPU核数,当你的电脑是四核的时候,你的电脑进程默认就是4个。
4.1.1参数详解
在Python中我们借助多进程包multiprocessing来进行多进程任务处理方式, multiprocessing模块提供了一个Process类来代表一个进程对象,
#Process参数 multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) #group分组 #target表示调用对象,即函数 #name表示进程的别名 #args表示调用对象的位置参数元组,即函数的参数 #kwargs表示调用对象的字典 #Process常用方法 close() 关闭进程 is_alive() 进程是否在运行 join() 等待join语句之前的所有程序执行完毕以后再继续往下运行,通常用于进程间的同步 start() 进程准备就绪,等待CPU调度 run() strat()调用run方法,如果实例化进程时没有传入target参数,这star执行默认run()方法 #Process常用属性 pid 进程ID name 进程名字
4.1.2建立一个子进程
下面的例子演示了启动一个子进程(即单进程)并等待其结束:
from multiprocessing import Process import os # 子进程要执行的代码def run_proc(name): print('Run child process %s (%s)...' % (name, os.getpid())) if __name__=='__main__': print('Parent process %s.' % os.getpid())#用来获取主进程的进程ID p = Process(target=run_proc, args=('test',))#实例化进程p,调用run_proc函数,传入参数对象args print('Child process will start.') p.start()#进程准备就绪 p.join()#待所有进程执行完毕以后执行后续操作 print('Child process end.')
运行结果如下:
Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.
一个子进程其实就和我们平常调用单一函数是一样的。
4.1.3建立多个子进程
建立多个子进程(即多进程),其实就是多个函数随机同步运行。
建立多进程有两种方法,一种是直接利用Process来建立多个子进程即可,如下:
from multiprocessing import Process import random,time def do_task(task): print('我正在做{}'.format(task)) time.sleep(random.randint(1,3)) def write_task(task): print('我正在写{}'.format(task)) time.sleep(random.randint(1,3)) if __name__ == "__main__": p1 = Process(target=do_task,args=('PPT',)) p2 = Process(target=write_task,args=('Sql',)) p1.start() p2.start()
输出结果为:
我正在做PPT 我正在写Sql
上面代码表示同时启动两个进程,且两个进程分别调用不同的函数,即做不同的任务。而且上面的任务数只有两个,当任务数(需要调用的函数)较多时,我们如果还用上述的方法创建多进程,就需要实例化多个进程对象,并且写多行p.start()比较麻烦,聪明的前辈们肯定不会用这么笨的方法,所以就有了进程池(Pool)。
multiprocessing.Pool = Pool(processes=None)#process为进程数
把上面的二进程用进程池表示以后的结果如下:
import multiprocessing import random,time def do_task(task): print('我正在做{}'.format(task)) time.sleep(random.randint(1,3)) def write_task(task): print('我正在写{}'.format(task)) time.sleep(random.randint(1,3)) if __name__ == "__main__": func_list=[do_task,write_task] args_list=["PPT","Sql"] pool=multiprocessing.Pool(2) for func,args in function_list,args_list: pool.apply_async(func,arg) print 'Waiting for all subprocesses done...' pool.close() pool.join() #调用join之前,一定要先调用close() 函数,否则会出错 print 'All subprocesses done.'
输出结果如下:
Waiting for all subprocesses done... 我正在做PPT 我正在写Sql All subprocesses done.
4.2多线程模式
多线程模式就是一次只启动一个进程,但是在这个进程里面可以启动多个线程,这样多个线程就可以一起执行多个任务,在Python中我们要启动多线程借助于threading模块,用于 启动多线程的模块还有_thread模块,但是threading模块是封装了_thread模块,且比较高级,所以我们一般使用threading模块即可。
4.2.1参数详解
启动多线程使用的是threading模块中的Thread类,构建时使用的参数和方法与Process基本一致,大家看看即可,这里就不赘述了。
#参数 Thread(group=None, target=None, name=None, args=(), kwargs={}) #方法 isAlive() get/setName(name) 获取/设置线程名 start() join()
4.2.2创建一个线程
创建一个线程就是调用一个函数。
import time, threading def do_chioce(task): print('我正在{}'.format(task)) time.sleep(random.randint(1,3)) if __name__ == "__main__": t = threading.Thread(target=do_chioce,args=('选PPT模板',)) t.start()
输出结果为:
我正在选PPT模板
4.2.3创建多个线程
创建多个线程就是调用多个函数。
import time, threading def do_chioce(task): print('我正在{}'.format(task)) time.sleep(random.randint(1,3)) def do_content(task): print('我正在{}'.format(task)) time.sleep(random.randint(1,3)) if __name__ == "__main__": t1 = threading.Thread(target=do_chioce,args=('选PPT模板',)) t2 = threading.Thread(target=do_content,args=('列PPT大纲',)) t1.start() t2.start()
输出结果为:
我正在选PPT模板 我正在列PPT大纲
4.3多进程+多线程
多进程+多线程就是一次启动多个进程,每个进程又启动多个线程,这样同时执行的任务就会很多,但是模型相对复杂,不建议使用。
相关推荐
- js中arguments详解
-
一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...
- firewall-cmd 常用命令
-
目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...
- epel-release 是什么
-
EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...
- FullGC详解 什么是 JVM 的 GC
-
前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...
-
2024-10-26 08:50 citgpt
- 跨域(CrossOrigin)
-
1.介绍 1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。 通俗讲...
- 微服务架构和分布式架构的区别
-
1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...
- 深入理解与应用CSS clip-path 属性
-
clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...
-
2024-10-25 11:51 citgpt
- Request.ServerVariables 大全
-
Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...
- python操作Kafka
-
目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...
- Runtime.getRuntime().exec详解
-
Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...
- promise.all详解 promise.all是干什么的
-
promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...
-
2024-10-24 16:21 citgpt
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracleclient (56)
- springbatch (59)
- oracle恢复数据 (56)
- 简单工厂模式 (68)
- 函数指针 (72)
- fill_parent (135)
- java配置环境变量 (140)
- linux文件系统 (56)
- 计算机操作系统教程 (60)
- 静态ip (63)
- notifyicon (55)
- 线程同步 (58)
- xcode 4 5 (60)
- 调试器 (60)
- c0000005 (63)
- html代码大全 (61)
- header utf 8 (61)
- 多线程多进程 (65)
- require_once (60)
- 百度网盘下载速度慢破解方法 (72)
- 谷歌浏览器免费入口 (72)
- npm list (64)
- 网站打开速度检测 (59)
- 网站建设流程图 (58)
- this关键字 (67)