Python程序实现多进程(multiprocessing)

Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。
子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

进程 multiprocessing

示例代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 进程调用

from multiprocessing import Process
import os

def run_proc(name):
    print("运行子进程 %s (%s)" % (name, os.getpid()))

if __name__ == "__main__":
    print("父进程 %s" % (os.getpid()))

    # 调用子进程函数
    p = Process(target = run_proc, args = ("test", ))

    print("子进程, 即将启动")
    p.start()
    p.join()
    print("子进程,调用结束")

运行结果

D:\PythonProject>python main.py
父进程 4552
子进程, 即将启动
运行子进程 test (5632)
子进程,调用结束

线程池 Pool

运行示例

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 线程池 Pool 批量创建子进程

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print("运行子进程 %s (%s)"%(name, os.getpid()))

    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print("子进程 %s 运行 %0.2f 秒." % (name, (end-start)))


if __name__ == "__main__":
    print("父进程为 %s" % os.getpid())

    # 线程池,最多同时运行4个进程
    p = Pool(4)

    # 批量产生 5 个 进程
    for i in range(5):
        # 调用子进程函数
        p.apply_async(long_time_task, args=(i,))

    print("等待所有子进程完成")
    p.close()
    p.join()
    print("所有子进程运行完毕")

运行结果

D:\PythonProject>python main.py
父进程为 8536
等待所有子进程完成
运行子进程 0 (808)
运行子进程 1 (2728)
运行子进程 2 (7876)
运行子进程 3 (3872)
子进程 3 运行 0.59 秒.
运行子进程 4 (3872)
子进程 2 运行 1.10 秒.
子进程 0 运行 1.59 秒.
子进程 1 运行 1.87 秒.
子进程 4 运行 2.57 秒.
所有子进程运行完毕

进程间通信

示例代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 进程间通信

# multiprocessing 模块包装了底层的机制,提供了Queue,Pipes等多种方式交换数据
from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码
def write(q):
    print("进程 %s 写数据" % os.getpid())

    for value in [1,2,3]:
        print("数据 %d 写入队列中..." % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码
def read(q):
    print("进程 %s 读数据" % os.getpid())
    while True:
        value = q.get(True)
        print("读出来的数据是 %d" % value)

if __name__ == "__main__":

    # 父进程创建Queue,并传给各个子进程
    q = Queue()

    # 启动子进程 pw,写入
    pw = Process(target = write, args = (q,))
    pw.start()

    # 启动子进程 pr, 读取
    pr = Process(target = read, args = (q,))
    pr.start()

    # 等待 pw 结束
    pw.join()

    # pr 是无限循环,强行终止
    pr.terminate()

运行结果

D:\PythonProject>python main.py
进程 9032 写数据
数据 1 写入队列中...
进程 3808 读数据
读出来的数据是 1
数据 2 写入队列中...
读出来的数据是 2
数据 3 写入队列中...
读出来的数据是 3