进程是用来运行程序的
python的os模块封装了常见的系统调用,其中就包括fork,可以在Linux下轻松创建子进程。
fork函数一旦调用成功,系统会产生一个原来进程的克隆,原进程升级为父进程。
进程的几个概念:
孤儿进程:
子进程还未运行完成,父进程已经结束,父进程死掉后,子进程会被其他进程托管,通常是init进程(pid=1)
僵尸进程:
子进程已经运行完成,但是父进程未对其进行回收,此时子进程仍占用着系统资源
守护进程:
守护进程是后台运行的一些特殊进程:
守护进程在系统引导的时候启动,并且一直运行直到系统关闭
只在需要的时候才启动,完成任务后就自动结束
在linux环境下,可以使用os.fork()来生成子进程,子进程会复制一份一模一样的数据来执行当前程序
os.fork()生成子进程
值得注意的是调用这个会返回一个值,父进程为子进程的pid号,而子进程的此id为0,所以我们可以以此来判断当前运行的是父进程还是子进程
os.getpid()获取当前进程id
os.getppid()获取父进程id
下面的例子:
import os
import time
rpid = os.fork()
if rpid < 0:
print("fork调用失败。")
elif rpid == 0:
print("我是子进程(%s),我的父进程是(%s),rpid是(%s)" % (os.getpid(), os.getppid(), rpid))
print("当前时间是{}".format(time.time()))
else:
print("我是父进程(%s),我的子进程是(%s),rpid是(%s)" % (os.getpid(), rpid, rpid))
print("当前时间是{}".format(time.time()))
time.sleep(1)
如果父进程与子进程运行间隔时间过短可能出现子进程创建失败的情况,所以加上time.sleep等待一秒再创建子进程
执行结果我是父进程(2655),我的子进程是(2656),rpid是(2656)
当前时间是1524493165.4608128
我是子进程(2656),我的父进程是(2655),rpid是(0)
当前时间是1524493165.4615178方法只在linux上适用,python内置了multiprocessing模块提供了一个Process类来代表一个进程对象。
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
Process的函数申明:
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
name:为当前进程实例的别名;
group:大多数情况下用不到;
Process类常用方法:
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
terminate():不管任务是否完成,立即终止;
Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:当前进程实例的PID值;
from multiprocessing import Process
import time
import os
def fun():
print("ppid:{},pid:{},实例id:{}".format(os.getppid(), os.getpid(), p.pid))
p = Process(target=fun, name="testfun")
print("process实例名称:{}".format(p.name))
p.start()
运行结果:
process实例名称:testfun
ppid:2864,pid:2865,实例id:2865
可以看到生成的实例进程运行了fun程序
另外一种生成进程的方式,就是用继承类去创建生成进程,前面说过run方法会在没有给定target参数时运行,所以我们将方法定义在fun里就行了
from multiprocessing import Process
import os
import time
class GenProcess(Process):
def __init__(self):
# 防止name,pid等属性丢失,直接调用Process初始化属性
Process.__init__(self)
def run(self):
print("子进程id:{},父进程id:{}".format(os.getpid(), os.getppid()))
time.sleep(10)
a = GenProcess()
a.start()
运行结果:
子进程id:2913,父进程id:2912
这就是Python生成进程的几种方式了
当我们需要产生多个进程池,一下循环产生很多进程可能就不那么好了,这时候就需要进程池了
通过Pool我们可以初始化并发进程数
from multiprocessing import Pool
import time
def genProcess(num):
print("这是第一种进程{}".format(num))
def genProcess2(num):
print("这是第二种进程{}".format(num))
# 初始化最大进程数
p = Pool(10)
for i in range(100):
# apply_async为异步非阻塞,apply为阻塞
p.apply_async(genProcess, (i,))
p.apply_async(genProcess2,(i,))
print("start----")
# 使其不再接受新任务
p.close()
p.join()