Python 学习, 多进程 实现

  1. 多进程: multiprocessing 模块
  • p = multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, * , daemon=None)

  • daemon 是守护进程,如果 daemon 为 True,那么当主进程结束时,无论子进程是否执行完成都会被杀死。

  • 用 Process 创建好进程后,需要启动进程 p.start()

  • p.join() 会阻塞当前进程,直到子进程执行完毕后继续执行

# 发送十封邮件

import time

import random

from multiprocessing import Process

def func(index):

    time.sleep(random.randint(1, 3))

    print('第%s封邮件发送完毕' % index)

if __name__ == '__main__':

    p_lst = []

    for i in range(10):

        p = Process(target=func, args=(i,))

        p.start()  # 先让所有子进程都启动

        p_lst.append(p)

    for p in p_lst:  # 再进行join阻塞

        p.join()

    print('10封邮件全部发送完毕')

对于多个子进程的情形,更简洁的方法是采用进程池:

multiprocessing.Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None)

processes :进程数量,默认使用 os.cpu_count(),主机最大 CPU 数量

initializer :可以为空,在 每一个 进程开始时会调用 initializer(*initargs), 比如在初始化的时候建立连接,连接重用。

maxtasksperchild:用户设置每个子进程执行多少个任务后重启。防止内存溢出、资源未释放等问题,默认不重启。 线程池 无此参数。

进程池(pool)中创建子进程的方法:

  • 普通调用:

pool.apply(func, args=(), kwds={}, callback=None, error_callback=None)

apply 对应的子进程 排队执行,实际非并行,按顺序执行每个子进程

pool.apply_async(func, args=(), kwds={})

apply_async 对应的每个子进程异步执行

pool.close() 关闭进程池,关闭后不能往 pool 中增加新的子进程,然后可以调用 join() 函数 等待已有子进程执行完毕

pool.join() 等待进程池中的子进程执行完毕,需要在 close() 函数后调用。

from multiprocessing import Pool, TimeoutError

import time

def f(x):

    time.sleep(x)

    return x

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = [pool.apply(f, (x, )) for x in range(4)]

        print(result)

    print(time.time() - start)

>>>

[0, 1, 2, 3]

6.39384913444519
from multiprocessing import Pool, TimeoutError

import time

def f(x):

    time.sleep(x)

    return x

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = [pool.apply_async(f, (x, )) for x in range(4)]

        print([res.get() for res in result])

    print(time.time() - start)

>>>

[0, 1, 2, 3]

3.37103271484375
  • 如果子进程有返回值,且返回值需要集中处理,可以采用 map 方式(子进程活动只允许 1 个参数)

pool.map(func, iterable, chunksize=None)

将iterable 的每个元素作为参数,应用func 函数。 这里是子进程阻塞进行。

pool.map_async(func, iterable, chunksize=None, callback=None, error_callback=None)

异步执行,返回 MapResult 实例 (有 get() 方法,获取结果)

from multiprocessing import Pool, TimeoutError

import time

def f(x):

    time.sleep(x)

    return x

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = pool.map(f, range(10))

        print(result)

    print(time.time() - start)

>>>

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

15.37588882446289
from multiprocessing import Pool, TimeoutError

import time

def f(x):

    time.sleep(x)

    return x

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = pool.map_async(f, range(10))

        print([res for res in result.get()])

    print(time.time() - start)

>>>

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

15.358932256698608
  • 如果内存不够用,可以采用 imap 迭代器方式:

pool.imap(func, iterable, chunksize=1)

pool.map 的迭代器版本,返回迭代器实例,pool.imap 远慢于 pool.map,但是对内存需求非常小

pool.imap_unordered(func, iterable, chunksize=1)

pool.imap() 的无序版本(不会按照调用顺序返回,而是按照结束顺序返回),返回迭代器实例。

from multiprocessing import Pool, TimeoutError

import time

def f(x):

    time.sleep(x)

    return x

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = pool.imap_unordered(f, range(10))

        print([res for res in result])

    print(time.time() - start)

>>>

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

15.357933759689331
  • 如果子进程活动具有多个参数,则不能直接使用map方式,需采用 starmap 方式:

pool.starmap(func, iterable, chunksize=None)

类似 pool.map(),但是 func 允许包含多个参数,iterable 的每个 元素也是 iterable(其每个元素作为func的参数),返回结果组成的list。

pool.starmap_async(func, iterable, chunksize=None, callback=None, error_callback=None)

pool.starmap() 的异步版本,返回 MapResult 实例。

from multiprocessing import Pool, TimeoutError

import time

def f(x, y):

    time.sleep(x)

    return y

if __name__ == '__main__':

    # start 4 worker processes

    start = time.time()

    with Pool(processes=4) as pool:

        result = pool.starmap_async(f, ((i, i) for i in range(10)))

        print([res for res in result.get()])

    print(time.time() - start)

>>>

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

15.355940103530884

参考资料:

https://iyaozhen.com/multiprocessing-and-threading-pool.html

https://www.cnblogs.com/Zzbj/p/9677645.html

https://zhuanlan.zhihu.com/p/46798399

你可能感兴趣的:(Python 学习, 多进程 实现)