Python多进程

115 阅读4分钟

参考:www.liaoxuefeng.com/wiki/101695…

进程

在操作系统中一个任务对应一个进程,如打开了word就启动了一个word进程

线程

一个进程下可以有多个线程至少一个线程

Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。

同时执行多个任务

  • 多进程模式:启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
  • 多线程模式:启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
  • 多进程 + 多线程模式 :启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。

multiprocessing 跨平台的多进程模块

# multiprocessing 中 使用 Process 代表一个进程对象

from multiprocessing import Process
import os


# 子进程运行的代码;
# proc_name: str ,表示 形参proc_name 需要是str类型 :
# https://docs.python.org/zh-cn/3.7/library/typing.html?highlight=typing#module-typing
def run_proc(proc_name: str):
    print(f'子进程运行,进程名称 { proc_name },其进程ID为:{ os.getpid() }')


def run_proc1():
    print(f'子进程运行,其进程ID为:{ os.getpid() }')


def run_proc2(name: str, now: str):
    print(f'子进程运行,进程名称 { name },其进程ID为:{ os.getpid() }, 当前时间 { now }')


if __name__ == '__main__':
    print(F"主进程ID:{ os.getpid() }")
    # 创建一个进程, target=需执行的函数, args=(需执行的函数参数, ), 可以是多个,1个也需要元组形式传递参数
    p = Process(target=run_proc, args=('测试进程', ))
    # 需执行函数无参数时,创建进程
    p1 = Process(target=run_proc1)
    p2 = Process(target=run_proc2, args=('name', 'fff', ))
    print("子进程将启动!")
    # start 方法启动进程
    p.start()
    p1.start()
    p2.start()
    # join 方法等待子进程结束后继续往下运行
    p.join()
    p1.join()
    p2.join()
    print('子进程结束')

Pool:进程池,批量创建进程

from multiprocessing import Pool

import os, time, random


def long_time_task(name):
    print(f'任务:{ name }({ os.getpid()})运行')
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print(f'任务 { name } 运行耗时 { end-start: .2f} 秒')


if __name__ == '__main__':
    print(f'主进程{ os.getpid() }')
    # 创建4个进程: Pool的默认大小是CPU的核心数,如果是8核cpu,你要提交至少9个线程才能看到效果
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('等待所有子进程运行完成')
    # 执行该方法后不能继续添加新的Process
    p.close()
    # 等待所有子进程执行完毕
    p.join()
    print('所有进程运行完毕!')

运行结果:

/Users/zy7y/PycharmProjects/demo/venv/bin/python /Users/zy7y/PycharmProjects/demo/pool_demo.py
主进程1893
等待所有子进程运行完成
任务:0(1894)运行
任务:1(1895)运行
任务:2(1896)运行
任务:3(1897)运行
任务 1 运行耗时  0.36 秒
任务:4(1895)运行
任务 2 运行耗时  1.08 秒
任务 0 运行耗时  2.77 秒
任务 3 运行耗时  2.81 秒
任务 4 运行耗时  2.45 秒
所有进程运行完毕!

结果解读:

任务0,1,2,3是立刻执行的,任务4是等前面某个任务完成后才执行,这是因为Pool的默认大小在本机是4,因此最多同时拥有4个进程

子进程(暂未理解)

subprocess实现方便启动一个子进程,控制其输入和输出

www.liaoxuefeng.com/wiki/101695…

进程间通信

Python的multiprocessing模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

import os
import random
import time
from multiprocessing import Process, Queue


# 写数据进程执行的代码
def write(q):
    print(f"用来写入的进程{os.getpid()}")
    for value in ['A', 'B', 'C']:
        print(f'把{ value }放入Queue(队列)中')
        q.put(value)
        time.sleep(random.random())


# 读数据进程执行的代码
def read(q):
    print(f'用来读取的进程{os.getpid()}')
    while True:
        value = q.get(True)
        print(f'从队列中获取 {value}')


if __name__ == '__main__':
    # 主进程创建Queue,并传递给各个子进程
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))

    # 启动子进程pw, 写入:
    pw.start()
    # 启动子进程pr, 读取:
    pr.start()

    # 等待pw结束
    pw.join()

    # pr进程是个死循环,无法自己结束,只能强行终止:
    pr.terminate()

运行结果:

/Users/zy7y/PycharmProjects/demo/venv/bin/python /Users/zy7y/PycharmProjects/demo/queue_demo.py
用来写入的进程2226A放入Queue(队列)中
用来读取的进程2227
从队列中获取 AB放入Queue(队列)中
从队列中获取 B
把C放入Queue(队列)中
从队列中获取 C

Process finished with exit code 0