今天我们来谈谈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需要一个小时,任务b需要一个小时,任务c需要一个小时。 每个任务20分钟后切换到另一个任务。 这样做的话,完成三个任务所需的总时间不会改变。 不仅不变,还可能增加。 在不同的任务之间切换需要成本。 因为wmdyf从一个任务切换到另一个任务时,很可能不记得去了多少。 另外,花点时间想想,为什么还要使用多进程/多线程这种任务处理方式呢? 正如第一部分所述,“多线程工作”可以减少您等待的时间,大大提高您的工作效率。
因为在实际工作中,有很多地方需要等待,比如等待Excel打开,或者等待Sql从数据中出来。 处理多进程/多线程任务的方式是充分利用这些等待时间。 让你的大脑、计算机的大脑(CPU )得到充分利用。 如果没有时间等待,多进程/多线程的任务处理方式可能不如单线程的。
04如何实现多进程和多线程
了解了什么是多进程和多线程,以及如何提高任务处理的效率后,请进入硬盘部分。 那就是具体的多进程/多线程如何实现“同时”处理多任务。
实现多任务处理的方法主要有以下:种
1、多进程模式
2、多线程模式
3、多进程多线程
同时执行多个任务通常需要彼此通信和协调,而不是各任务之间没有关联。 任务1可能需要等待任务2完成,任务3和任务4可能无法同时执行。 因此,多线程和多线程程序的复杂性远远高于刚才编写的单线程程序。
4.1多进程模式
多进程是指一次启动多个进程。 每个进程只有一个线程,但多个进程可以同时执行多个任务。 一般进程数默认为电脑的CPU内核数,如果wmdyf的电脑是四核的话,你的电脑进程默认为4个。
4.1.1参数详细信息
Python使用多进程软件包multiProcessing处理多进程任务。 multiprocessing模块提供了表示流程对象的process类。
#进程参数
multi processing.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多进程+多线程
多进程+多线程就是一次启动多个进程,每个进程又启动多个线程,这样同时执行的任务就会很多,但是模型相对复杂,不建议使用。