由于个人知识面有限,以下就说说我对python中多进程编程的理解,如果有错误的地方,请多多指教。
在python中有三种方式创建多进程:fork,process,pool

一: fork应用

import os

import time

print("只有主进程执行此语句")
#调用fork函数后,会产生2个值:子进程的pid和父进程的pid,
# 其中子进程的pid为0,父进程的pid为子进程的pid,其实就相当于返回了2个子进程号
#以下为os模块中fork函数的解释
#1.Fork a child process.
#2.Return 0 to child process and PID of child to parent process.

pid = os.fork() #调用os模块的fork函数创建进程
print("主进程和子进程都能执行此语句,进程id==%d"%os.getpid())

if pid == 0:
    #子进程执行代码块
    print("我是子进程,子进程id是%d,父进程id是%d"%(os.getpid(),os.getppid()))

elif pid > 0:
    #父进程执行的代码块
    #下句语句中的pid容易跟if判断中的pid混淆
    print("我是父进程,父进程id是%d,子进程id是%d"%(os.getpid(),pid))

os.getpid() 获取当前进程id
os.getppid() 获取父进程id

注意:1: fork函数只能在unix中运行。
2: 父进程和子进程执行没有先后顺序,执行顺序由系统根据相关规则调用。
3: 主进程不会等所有子进程结束后而结束。

二: process应用
由于window无法调用fork函数,如果要在window创建多进程,则需要用到multiprocessing模块,而multiprocessing模块就是跨平台版本的多进程模块。

from multiprocessing import Process
import time

def test():
    while True:
        print("1-----我是子进程")
        time.sleep(2)

p = Process(target=test)
p.start()
while True:
    print("2----我是主进程")
    time.sleep(2)

上处代码为使用Process类创建的实例

from multiprocessing import Process
import time
import os

def test1(interval):
    start = time.time()
    time.sleep(interval)
    print("我是test1,我的进程号是%d,我的父进程id是%d"%(os.getpid(),os.getppid()))
    end = time.time()

def test2(interval):
    start = time.time()
    time.sleep(interval)
    print("我是test2,我的进程号是%d,我的父进程id是%d"%(os.getpid(),os.getppid()))
    end = time.time()

p1 = Process(target=test1,args=(5,))
p1.start()
print("p1.pid = %d"%p1.pid)
p1.join()


p2 = Process(target=test2,args=(1,))
p2.start()
print("p2.pid = %d"%p2.pid)

上段代码中的join是指阻塞进程,当所有的对象进程都结束后其他进程才可继续向下执行程序。
此外: join函数可以加阻塞时间,如果加上时间,则表示阻塞系统指定时间,如p1.join(2),到达指定时间后,如果子进程没有结束,那么主进程可以和子进程同时执行。如果不指定阻塞时间,则表示等待对象进程执行完毕后,主进程才可继续向下运行。
注意:主进程会等待子进程的结束而结束
下面将介绍Process类中常用方法和属性
常用属性:
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
pid:当前进程实例的PID值;
常用方法:
start() 创建进程实例同时并启动进程
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒
terminate():不管任务是否完成,立即终止
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法,一般用于继承Process类中重写run方法

重写run方法案例如下:

from multiprocessing import Process
import time

start = time.time()

class MyProcess(Process):
    def __init__(self,num):
        super().__init__()
        self.num = num

    def run(self):
        start = time.time()
        print("子进程开始执行")
        time.sleep(self.num)
        end = time.time()
        print("子进程执行时间是%#.5f"%(end-start))

myProcess = MyProcess(2)
myProcess.start()
# myProcess.run()
# myProcess.join()
end = time.time()
print("主进程执行时间是%#.5f"%(end-start))

三: pool应用
使用场景和使用原理:
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。
Pool分为两种:apply_async 非阻塞式和apply 阻塞式
下面将这两种使用方法和区别进行介绍
apply_async 非阻塞式,以下是案例:

from multiprocessing import Pool
import time
import os
import random

start = time.time()
def work(num):
    start = time.time()
    time.sleep(random.random()*2)
    end = time.time()
    print("%d执行的进程id是%d,父进程id是%d,执行时间是%#.5f"%(num,os.getpid(),os.getppid(),(end-start)))

pool = Pool(3)
for i in range(0,10):
    # pool.apply_async(work,args=(i,)) #非阻塞式
    pool.apply(work, args=(i,))  #阻塞式

pool.close()
# pool.join()
#使用非阻塞式时打开下面for循环
#for j in range(0,12):
#   time.sleep(random.random()*2)
#   print("主进程的pid是%d,j==%d"%(os.getpid(),j))

end = time.time()
print("主进程的id是%d,运行时间是%d"%(os.getpid(),(end-start)))

当使用非堵塞式时,主进程和子进程同时执行,并且主进程不会等待子进程的结束而结束。
当使用堵塞式时,系统会等待一个进程结束之后在执行其他进程。这类似与单进程。

multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;