python多进程库_Python内置库:multiprocessing(多进程)

Python的多进程因为可以充分利用CPU多核的特点,所以通常用于计算密集型的场景或者需要大量数据操作的场景,而对于多线程,在某些语言中因为可以充分利用CPU,所以可能多线程的场景使用得多一点,但是在Python中,多线程只能在CPU的单核中运行,不能充分利用CPU多核的特点,所以Python多线程通常用于IO密集型的场景或者少量数据的并发操作场景。总而言之,Python的多线程只是并发执行,而不是真正的并行执行,而且只能在CPU单核上进行,所以如果需要进行大量的数据操作或者比较耗时的并行操作,那么就可以考虑使用多进程了。

本文只是根据官方文档简单记了一下multiprocessing模块中进程的基本操作,包括创建进程、进程启动方式、进程间通信、进程间同步、进程池,如果需要其他更多操作,可以参考此模块的官方中文文档

创建进程

实例化Process类创建一个进程对象,然后调用它的start方法即可生成一个新的进程(子进程)。Process进程对象的使用其实和多线程模块threading中的Thread线程对象非常相似,可以参考着来使用。

"""

简单示例:创建一个子进程

"""

import os

from multiprocessing import Process

def func(s):

# 输出传入的参数,当前子进程的进程ID,当前进程的父进程ID

print(s, os.getpid(), os.getppid())

# 注意:此处的if __name__ == '__main__'语句不能少

if __name__ == '__main__':

# 打印当前进程的进程ID

print(os.getpid())

print('main process start...')

# 创建进程对象

p = Process(target=func, args=('hello', ))

# 生成一个进程,并开始运行新的进程

p.start()

# 等待子进程运行完毕

p.join()

print('main process end!')

打印输出

13888

main process start...

hello 12484 13888

main process end!

Process类

Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None):group不用特别指定,使用默认就行;target表示需要调用的对象;name表示新进程的名称;args和kwargs表示传给target对象的元组参数和字典参数;daemon是一个关键字参数,使用时必须指定参数名,表示是否为守护进程,如果不指定则默认继承自调用者进程。

注:需要注意的是如果重写了Process的__init__方法,那么在做任何操作之前需要先调用Process.__init__()方法。

常用的方法和属性:

run:表示进程活动的方法,即此方法的运行是在新开启的进程中,如果在子类中重写了此方法,应该在此方法中调用target对象。

start():用于启动进程活动(注意此方法是在调用者进程中,而不是在新的进程中),并用于保证run方法在一个新的进程中被调用。

join([timeout]):如果timeout参数没有指定(默认),则会阻塞当前进程直到调用join方法的进程(子进程)运行结束,如果指定了timeout参数,则会阻塞指定的秒数。注意,join方法不能在start方法之前调用,但join方法可以调用多次。如果想要知道进程的状态(包括是否结束),可以查看进程对象的exitcode值来进行判断。

name:进程名称,没什么实际意义,只是用来表示进程,多个进程可能有相同的名称。如果没有特别指定,则默认命名格式为Process-N1:N2:N3...。

is_alive():此进程是否存活。

damemon:表示进程是否为守护进程,这个标识必须在start()方法调用之前进行设置,如果不设置,默认继承创建者进程。当一个进程终止时,会尝试终止它的所有守护子进程,需要注意的是,守护进程是不允许创建子进程的。

pid:进程ID。

exitcode:进程退出状态,当进程还未结束时,值为None,如果进程结束了,会用一个负值-N表示结束信号。

authkey:进程的身份验证密钥(字节字符串),当multiprocessing被初始化时,主进程会使用os.urandom()分配一个随机的字符串,当创建Process子进程时,子进程会继承其父进程的身份密钥,当然,你也可以修改子进程的身份密钥。

sentinel:系统对象的数字句柄,当进程结束时将变为“ready”。如果想要使用multiprocessing.connection.wait()一次等待多个事件,那可以使用这个值,否则调用join()方法会更简单。

terminate():终止进程,在Unix上使用的是SIGTERM信号,在Windows上使用的是TerminateProcess()。注意,进程的后代进程不会被终止(会变成“孤儿”进程)。另外,如果被终止的进程在使用Pipe或Queue时,它们有可能会被损害,并无法被其他进程使用;如果被终止的进程已获得锁或信号量等,则有可能导致其他进程死锁。所以请谨慎使用此方法。

kill():也是终止进程,但是在Unix上使用的是SIGKILL信号。

close():关闭Process对象,并释放与之关联的所有资源,如果底层进程仍在运行,则会引发ValueError。而且,一旦close()方法成功返回,Process对象的大多数方法和属性也可能会引发ValueError。

进程启动方式

multiprocessing模块中进程的启动方式有三种spawn、fork和forkserver,在不同的系统平台上它们的使用和默认设置也会有所不同:

spawn:由父进程启动一个新的Python解释器Process子进程,子进程只会继承run()方法中所必需的资源,而父进程中那些非必需的文件描述符和句柄是不会被继承的。而且,相对于使用fork和forkserver来启动进程,spawn方法启动是非常慢的。spawn启动方式可以在Unix和Windows上使用,且Windows上默认使用此方法启动。

fork:父进程使用os.fork()来产生一个新的Python解释器分叉(fork)子进程,子进程在开始时与父进程是相同的,即子进程会继承父进程拥有的所有资源。这种方式的问题在于当父进程中存在多线程时,启动的新的子进程的安全性需要自己留意。fort启动方式只能在Unix中使用,且也是Unix中默认的启动方式。

forkserver:程序会先使用forkserver启动一个服务器进程,然后当需要运行一个新的进程时,父进程会先连接到服务器并请求其分叉(fork)一个新的进程。 相比于fork启动方式,由于forkserver启动的服务器进程是单线程的进程,所以由它通过os.fork()启动的进程是安全的(此服务器进程没有多线程的情况)。forkserver启动方式可以在Unix平台使用,并支持通过Unix管道传递文件描述符。

设置统一的启动方式:可以在程序运行开始时,即if __name__ == "__main__"中使用multiprocessing.set_start_method(method)函数来设置启动方式,设置时传入对应启动方式的字符串即可("spawn"/"fork"/"forkserver")。但是需要注意两点,一是需要在if __name__ &#

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值