Python 多进程

 

1. 进程

windows下不支持os.fork() 方法来启动多个进程

Python 在 multiprocessing 模块下提供了 Process 来创建新进程。与线程类似的是,使用 Process 创建新进程也有两种方式:

  • 以指定函数作为 target,创建 Process 对象即可创建新进程。常用
  • 继承 Process 类,并重写它的 run() 方法来创建进程类,程序创建 Process 子类的实例作为进程。(与线程继承Thread类相似,不常用)

Process 类方法和属性:

  • run():重写该方法可实现进程的执行体。
  • start():该方法用于启动进程。
  • join([timeout]):该方法类似于线程的 join() 方法,当前进程必须等待被 join 的进程执行完成才能向下执行。
  • name:该属性用于设置或访问进程的名字。
  • is_alive():判断进程是否还活着。
  • daemon:该属性用于判断或设置进程的后台状态。
  • pid:返回进程的 ID。
  • authkey:返回进程的授权 key。
  • terminate():中断该进程。
# -*- coding: utf-8 -*-

from multiprocessing import Process
import os


# 子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))


# multiprocessing模块提供了一个Process类来代表一个进程对象
# 通过 multiprocessing.Process 来创建并启动进程时,程序必须先判断if __name__=='__main__':,否则可能引发异常。
if __name__ == '__main__':
    print('Parent process %s.' % os.getpid())
    for i in range(5):
        p = Process(target=run_proc, args=(i,))
        print('Child process will start.')
        p.start()  # 启动进程
        p.join()  # 等待子进程执行结束后,再继续向下运行。
    print('Child process end')

2. 进程池

进程池与线程池一样实现了上下文管理协议,因此程序可以使用 with 子句来管理进程池,可以避免程序主动关闭进程池。

通过multiprocessing 模块的 Pool() 函数创建进程池

进程池具有如下常用方法:

  • apply(func[, args[, kwds]]):将 func 函数提交给进程池处理。其中 args 代表传给 func 的位置参数,kwds 代表传给 func 的关键字参数。该方法会被阻塞直到 func 函数执行完成。
  • apply_async(func[, args[, kwds[, callback[, error_callback]]]]):这是 apply() 方法的异步版本,该方法不会被阻塞。其中 callback 指定 func 函数完成后的回调函数,error_callback 指定 func 函数出错后的回调函数。
  • map(func, iterable[, chunksize]):类似于 Python 的 map() 全局函数,只不过此处使用新进程对 iterable 的每一个元素执行 func 函数。

       Python中线程池与进程池的map()方法使用方式相同

  • map_async(func, iterable[, chunksize[, callback[, error_callback]]]):这是 map() 方法的异步版本,该方法不会被阻塞。其中 callback 指定 func 函数完成后的回调函数,error_callback 指定 func 函数出错后的回调函数。
  • imap(func, iterable[, chunksize]):这是 map() 方法的延迟版本。
  • imap_unordered(func, iterable[, chunksize]):功能类似于 imap() 方法,但该方法不能保证所生成的结果(包含多个元素)与原 iterable 中的元素顺序一致。
  • starmap(func, iterable[,chunksize]):功能类似于 map() 方法,但该方法要求 iterable 的元素也是 iterable 对象,程序会将每一个元素解包之后作为 func 函数的参数。
  • close():关闭进程池。在调用该方法之后,该进程池不能再接收新任务,它会把当前进程池中的所有任务执行完成后再关闭自己。
  • terminate():立即中止进程池。
  • join():等待所有进程完成。
# -*- coding: utf-8 -*-

from multiprocessing import Pool
import os, time, random


def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))


def func(num):
    res = num * num
    print(res)


if __name__ == '__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    l = range(1, 5)
    # 进程池的 map() 方法会为 iterables 的每个元素启动一个进程,以并发方式来执行 func 函数
    p.map(func, l) 
 
    # apply_async() 将 任务 提交给进程池,由进程池负责启动
    # for i in range(8):
    #     p.apply_async(long_time_task, args=(i,))   
   
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

3. 进程间通信 

Python 为进程通信提供了两种机制:

  1. Queue:一个进程向 Queue 中放入数据,另一个进程从 Queue 中读取数据。
  2. Pipe:Pipe 代表连接两个进程的管道。程序在调用 Pipe() 函数时会产生两个连接端,分别交给通信的两个进程,接下来进程既可从该连接端读取数据,也可向该连接端写入数据。

multiprocessing 模块下的 Queue 和 queue 模块下的 Queue 基本类似,它们都提供了 qsize()、empty()、full()、put()、put_nowait()、get()、get_nowait() 等方法。区别只是 multiprocessing 模块下的 Queue 为进程提供服务,queue 模块下的 Queue 为线程提供服务。

# -*- coding: utf-8 -*-

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

'''
在Quene 已空的情况下,程序使用 get() 方法尝试取出元素将会阻塞线程,在队列已满的情况下继续放入元素,也会阻塞线程

队列  FIFO 先进先出   
LIFO  后进先出
'''


# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())


# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)


if __name__ == '__main__':
    # 进程间通信通过 quene  pipes等实现
    # 父进程创建Queue,并传给各个子进程:

    q = Queue()
    # Process 以指定函数作为target创建新进程
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值