Python基础(9) 多进程

文章目录

    • 0. 前言
    • 1. ProcessPoolExecutor
    • 2. multiprocessing
      • 2.1. Process
      • 2.2. Pool


0. 前言

  • Python中的多线程与多进程:
    • Python中由于全局解释器(Global Interpreter Lock, GIL)的关系,多线程程序默认只能使用CPU的一个核。
    • Python多线程适用于IO密集型任务。
    • Python多进程则能够跳过GIL的限制,使用多个CPU核,适用于计算密集型任务。
  • Python中的多进程主要通过 ProcessPoolExecutormultiprocessing 实现。
    • 需要注意的是,ProcessPoolExecutor 是通过 multiprocessing 包实现的。
  • 参考资料:
    • 官方文档:ProcessPoolExecutor
    • 官方文档:multiprocessing

1. ProcessPoolExecutor

  • ProcessPoolExecutor 的是 concurrent.futures.Executor 的子类。
  • 构造器:ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=())
    • max_workers:设置最大进程数量。
    • initializer & initargs:在创建每个进程时会调用的函数,以及函数对应参数。
    • mp_context:多进程上下文。
  • 主要方法:
    • submit(fn, *args, **kwargs):提交任务,返回Future对象。
    • shutdown(wait=True):关闭线程池,如果wait=True则等待所有启程执行完毕后结束才,否则就是马上返回(但正在执行的会继续执行完毕)。
    • map(func, *iterables, timeout=None, chunksize=1)
  • 举例
import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()

2. multiprocessing

  • 提供了类似 threading 的API。

2.1. Process

  • 类似于 threading.Thread,用于创建单个进程。
  • threading.Thread 相同的API:
    • start():启动进程
    • run():启动进城后执行的函数
    • join():当A进程调用B进程的join()方法后,A进程会等待B进程执行完毕后再继续执行下一步。
    • name:进程名称。
    • daemon:是否为守护进程,如果需要改变数值,则需要在执行 start 前完成。
    • is_alive():判断是否正在执行。
  • 独有的API:
    • pid
    • terminate():终止进程,不会执行退出处理程序和finally子句等
    • kill():与 terminate() 相同。
    • close():关闭Process对象,释放对应资源。

2.2. Pool

  • 进程池的另一种实现,全名为 multiprocessing.pool.Pool
  • 初始化函数:Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
    • processes:最大进程数量,默认为 os.cpu_count()
    • initializer & initargs:启动进程时会调用的函数以及对应的参数。
    • context:进程池上下文。
    • maxtasksperchild:退出或被一个新的工作进程代替之前能完成的任务数量。
      • 默认为None,即生命周期与进程池相同。
      • 主要作用是释放资源。
  • 主要方法:
    • apply(func[, args[, kwds]]):使用进程池中某一个进程调用该方法。会阻塞直到返回结果
    • apply_async(func[, args[, kwds[, callback[, error_callback]]]])
      • apply的变种,不会阻塞
      • 如果正常执行则会调用 callback 对象,该对象接受单个参数(猜测就是函数输出)。
      • 如果出错了,则会调用 error_callback 对象,该对象接受单个参数,该参数是抛出的异常对象。
    • map(func, iterable[, chunksize])/map_async:内置函数map()的并行版本。
      • 这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而(近似)指定每个块的大小可以。
      • 注意对于很长的迭代对象,可能消耗很多内存。可以考虑使用 imap() 或 imap_unordered() 并且显示指定 chunksize 以提升效率。
    • starmap(func, iterable[, chunksize])/starmap_async:与map类似,猜测就是等价于对iterable对象再包裹上一层func
    • imap(func, iterable[, chunksize])map的延迟执行版本。
    • imap_unordered(func, iterable[, chunksize])
      • imap相同,区别在于通过迭代器返回的结果是任意的。
    • close():阻止后续任务提交到进程池,当所有任务执行完成后,工作进程会退出。
    • terminate():不必等待未完成的任务,立即停止工作进程。当进程池对象呗垃圾回收时, 会立即调用 terminate() 。
    • join():等待工作进程结束。
      • 调用 join() 前必须先调用 close() 或者 terminate()
  • 举例:
from multiprocessing import Pool
import time

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(processes=4) as pool:         # start 4 worker processes
        result = pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously in a single process
        print(result.get(timeout=1))        # prints "100" unless your computer is *very* slow

        print(pool.map(f, range(10)))       # prints "[0, 1, 4,..., 81]"

        it = pool.imap(f, range(10))
        print(next(it))                     # prints "0"
        print(next(it))                     # prints "1"
        print(it.next(timeout=1))           # prints "4" unless your computer is *very* slow

        result = pool.apply_async(time.sleep, (10,))
        print(result.get(timeout=1))        # raises multiprocessing.TimeoutError

你可能感兴趣的:(Python)