[python基础]进程池基础知识

进程池

为什么要有进程池

在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程

进程池的概念。

定义一个进程池,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果

设置进程池class multiprocessing.pool.Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])

一个进程池对象,它控制可以提交作业的工作进程池

它支持带有超时回调异步结果,以及一个并行map 实现

参数说明
processes使用的工作进程数目。如果 processesNone,则使用 os.cpu_count() 返回的值
initializer每个工作进程启动时要执行的可调用对象,默认为None。如果initializer不为None,则每个工作进程在启动时都会调用initializer(*initargs)
initargs传递给initializer的参数数组
maxtasksperchild一个工作进程在它退出或被一个新的工作进程代替之前能完成的任务数量,为了释放未使用的资源。默认的*maxtasksperchild* 是 None,意味着工作进程的寿命与线程池一致
context可被用于指定启动的工作进程的上下文,通常一个进程池是使用函数 multiprocessing.Pool() 或者一个上下文对象的 Pool() 方法创建的。在这两种情况下, context 都是适当设置的。注意,进程池对象的方法只有创建它的进程能够调用

注意:进程池对象的方法只有创建他的进程能够调用

警告:

multiprocessing.pool对象具有需要正确管理的内部资源 (像任何其他资源一样),具体方式是将进程池用作上下文管理器,或者手动调用 close()terminate()

未做此类操作将导致进程在终结阶段挂起

请注意:

依赖垃圾回收器来销毁进程池是 不正确 的做法,因为 CPython 并不保证会调用进程池终结程序

multiprocessing.Pool的方法

函数说明
apply(func[, args[, kwds]])使用args参数以及 kwds命名参数调用func,另外 func只会在一个进程池中的一个工作进程中执行
apply_async(func[,args[,kwds[,callback[,error_callback]]]])方法的一个变种,返回一个AsyncResult对象。如果指定了 callback,它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback`,如果指定了 error_callback , 它必须是一个接受单个参数可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。回调函数应该立即执行完成,否则会阻塞负责处理结果的线程
map(func,iterable[,chunksize])内置 map()函数的并行版本 (但它只支持一个 iterable 参数)它会保持阻塞直到获得结果。这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而指定每个块的大小可以。注意对于很长的迭代对象,可能消耗很多内存。可以考虑使用 imap()或 imap_unordered() 并且显示指定 chunksize 以提升效率
map_async(func,iterable[,chunksize[,callback[,error_callback]]])map() 方法的一个变种,返回一个AsyncResult对象。如果指定了 callback , 它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback 。如果指定了 error_callback , 它必须是一个接受单个参数的可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。回调函数应该立即执行完成,否则会阻塞负责处理结果的线程
imap(func,iterable[,chunksize])map() 的延迟执行版本。chunksize 参数的作用和 map()方法的一样。对于很长的迭代器,给 chunksize 设置一个很大的值会比默认值 1 极大 地加快执行速度。同样,如果chunksize1 , 那么 imap() 方法所返回的迭代器的 next() 方法拥有一个可选的 timeout 参数: 如果无法在 timeout 秒内执行得到结果,则next(timeout) 会抛出 multiprocessing.TimeoutError异常
imap_unordered(func,iterable[,chunksize])imap()相同,只不过通过迭代器返回的结果是任意的。(当进程池中只有一个工作进程的时候,返回结果的顺序才能认为是"有序"的)
starmap(func,iterable[,chunksize])map()类似,不过 iterable 中的每一项会被解包再作为函数参数。比如可迭代对象 [(1,2), (3, 4)] 会转化为等价于 [func(1,2), func(3,4)] 的调用。3.3 新版功能.`s
starmap_async(func,iterable[,chunksize[,callback[, error_callback]]])相当于starmap()map_async() 的结合,迭代 iterable 的每一项,解包作为 func 的参数并执行,返回用于获取结果的对象
close()阻止后续任务提交到进程池,当所有任务执行完成后,工作进程会退出。如果操作持续挂起,他们将在工作进程中之前完成
terminate()不必等待未完成的任务,立即停止工作进程。当进程池对象呗垃圾回收时, 会立即调用 terminate()join()等待工作进程结束。调用 join()前必须先调用 close()或者 terminate()._enter_ 返回进程池对象, __exit__() 会调用 terminate()
join()等待工作进程结束。调用 join() 前必须先调用close() 或者 terminate()
同步线程池和异步线程池对比:

同步线程池案例:

apply实现同步线程

import multiprocessing
import os
import time


def work(n):
    print("{}-->is working!".format(os.getpid()))
    time.sleep(1)
    return n**2


if __name__ == '__main__':
    print("当前的CPU内核数为%d" % os.cpu_count())

    p = multiprocessing.Pool(5)
    
    res_l = []

    for i in range(10):
        res = p.apply(work, args=(i, ))
        res_l.append(res)

    print(res_l)

map实现同步线程

import multiprocessing
import os
import time


def test(num):
    print("{}-->进程开始了".format(os.getpid()))
    time.sleep(1)
    return num**2


if __name__ == '__main__':
    p = multiprocessing.Pool(5)

    content = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(p.map(test, content))

异步线程池案例:

apply_async实现异步线程池

import multiprocessing
import os
import time


def work(n):
    print("{}-->is working!".format(os.getpid()))
    time.sleep(1)
    return n**2


if __name__ == '__main__':
    print("当前的CPU内核数为%d" % os.cpu_count())

    p = multiprocessing.Pool(5)

    res_l = []

    for i in range(10):
        res = p.apply_async(work, args=(i,))
        res_l.append(res)

    p.close()
    p.join()

    for res in res_l:
        print(res.get(), end=" ")

map_async实现异步线程池

import multiprocessing
import os
import time


def test(num):
    print("{}-->进程开始了".format(os.getpid()))
    time.sleep(1)
    return num**2


if __name__ == '__main__':
    p = multiprocessing.Pool(5)

    content = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    content = p.map_async(test, content)

    p.close()
    p.join()

    print(content.get())

AsyncResult对象

class multiprocessing.pool.AsyncResult对象

multiprocessing.pool.Apply_syncmultiprocessing.pool.map_async返回对象

multiprocessing.pool.AsyncResult的方法
函数说明
get([timeout])用于获取执行结果.如果 timeout 不是 None 并且在 timeout 秒内仍然没有执行完得到结果,则抛出 multiprocessing.TimeoutError 异常。如果远程调用发生异常,这个异常会通过 get()重新抛出
wait([timeout])阻塞,直到返回结果,或者 timeout 秒后超时
ready()返回执行状态,是否已经完成。
successful()判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError
terminate()立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作,如果P(multiprocessing.Prosse)被回收,则自动调用此方法

进程池

为什么要有进程池

在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程

进程池的概念。

定义一个进程池,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果

设置进程池class multiprocessing.pool.Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])

一个进程池对象,它控制可以提交作业的工作进程池

它支持带有超时回调异步结果,以及一个并行map 实现

参数说明
processes使用的工作进程数目。如果 processesNone,则使用 os.cpu_count() 返回的值
initializer每个工作进程启动时要执行的可调用对象,默认为None。如果initializer不为None,则每个工作进程在启动时都会调用initializer(*initargs)
initargs传递给initializer的参数数组
maxtasksperchild一个工作进程在它退出或被一个新的工作进程代替之前能完成的任务数量,为了释放未使用的资源。默认的*maxtasksperchild* 是 None,意味着工作进程的寿命与线程池一致
context可被用于指定启动的工作进程的上下文,通常一个进程池是使用函数 multiprocessing.Pool() 或者一个上下文对象的 Pool() 方法创建的。在这两种情况下, context 都是适当设置的。注意,进程池对象的方法只有创建它的进程能够调用

注意:进程池对象的方法只有创建他的进程能够调用

警告:

multiprocessing.pool对象具有需要正确管理的内部资源 (像任何其他资源一样),具体方式是将进程池用作上下文管理器,或者手动调用 close()terminate()

未做此类操作将导致进程在终结阶段挂起

请注意:

依赖垃圾回收器来销毁进程池是 不正确 的做法,因为 CPython 并不保证会调用进程池终结程序

multiprocessing.Pool的方法

函数说明
apply(func[, args[, kwds]])使用args参数以及 kwds命名参数调用func,另外 func只会在一个进程池中的一个工作进程中执行
apply_async(func[,args[,kwds[,callback[,error_callback]]]])方法的一个变种,返回一个AsyncResult对象。如果指定了 callback,它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback`,如果指定了 error_callback , 它必须是一个接受单个参数可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。回调函数应该立即执行完成,否则会阻塞负责处理结果的线程
map(func,iterable[,chunksize])内置 map()函数的并行版本 (但它只支持一个 iterable 参数)它会保持阻塞直到获得结果。这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而指定每个块的大小可以。注意对于很长的迭代对象,可能消耗很多内存。可以考虑使用 imap()或 imap_unordered() 并且显示指定 chunksize 以提升效率
map_async(func,iterable[,chunksize[,callback[,error_callback]]])map() 方法的一个变种,返回一个AsyncResult对象。如果指定了 callback , 它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback 。如果指定了 error_callback , 它必须是一个接受单个参数的可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。回调函数应该立即执行完成,否则会阻塞负责处理结果的线程
imap(func,iterable[,chunksize])map() 的延迟执行版本。chunksize 参数的作用和 map()方法的一样。对于很长的迭代器,给 chunksize 设置一个很大的值会比默认值 1 极大 地加快执行速度。同样,如果chunksize1 , 那么 imap() 方法所返回的迭代器的 next() 方法拥有一个可选的 timeout 参数: 如果无法在 timeout 秒内执行得到结果,则next(timeout) 会抛出 multiprocessing.TimeoutError异常
imap_unordered(func,iterable[,chunksize])imap()相同,只不过通过迭代器返回的结果是任意的。(当进程池中只有一个工作进程的时候,返回结果的顺序才能认为是"有序"的)
starmap(func,iterable[,chunksize])map()类似,不过 iterable 中的每一项会被解包再作为函数参数。比如可迭代对象 [(1,2), (3, 4)] 会转化为等价于 [func(1,2), func(3,4)] 的调用。3.3 新版功能.`s
starmap_async(func,iterable[,chunksize[,callback[, error_callback]]])相当于starmap()map_async() 的结合,迭代 iterable 的每一项,解包作为 func 的参数并执行,返回用于获取结果的对象
close()阻止后续任务提交到进程池,当所有任务执行完成后,工作进程会退出。如果操作持续挂起,他们将在工作进程中之前完成
terminate()不必等待未完成的任务,立即停止工作进程。当进程池对象呗垃圾回收时, 会立即调用 terminate()join()等待工作进程结束。调用 join()前必须先调用 close()或者 terminate()._enter_ 返回进程池对象, __exit__() 会调用 terminate()
join()等待工作进程结束。调用 join() 前必须先调用close() 或者 terminate()
同步线程池和异步线程池对比:

同步线程池案例:

apply实现同步线程

import multiprocessing
import os
import time


def work(n):
    print("{}-->is working!".format(os.getpid()))
    time.sleep(1)
    return n**2


if __name__ == '__main__':
    print("当前的CPU内核数为%d" % os.cpu_count())

    p = multiprocessing.Pool(5)
    
    res_l = []

    for i in range(10):
        res = p.apply(work, args=(i, ))
        res_l.append(res)

    print(res_l)

map实现同步线程

import multiprocessing
import os
import time


def test(num):
    print("{}-->进程开始了".format(os.getpid()))
    time.sleep(1)
    return num**2


if __name__ == '__main__':
    p = multiprocessing.Pool(5)

    content = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(p.map(test, content))

异步线程池案例:

apply_async实现异步线程池

import multiprocessing
import os
import time


def work(n):
    print("{}-->is working!".format(os.getpid()))
    time.sleep(1)
    return n**2


if __name__ == '__main__':
    print("当前的CPU内核数为%d" % os.cpu_count())

    p = multiprocessing.Pool(5)

    res_l = []

    for i in range(10):
        res = p.apply_async(work, args=(i,))
        res_l.append(res)

    p.close()
    p.join()

    for res in res_l:
        print(res.get(), end=" ")

map_async实现异步线程池

import multiprocessing
import os
import time


def test(num):
    print("{}-->进程开始了".format(os.getpid()))
    time.sleep(1)
    return num**2


if __name__ == '__main__':
    p = multiprocessing.Pool(5)

    content = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    content = p.map_async(test, content)

    p.close()
    p.join()

    print(content.get())

AsyncResult对象

class multiprocessing.pool.AsyncResult对象

multiprocessing.pool.Apply_syncmultiprocessing.pool.map_async返回对象

multiprocessing.pool.AsyncResult的方法
函数说明
get([timeout])用于获取执行结果.如果 timeout 不是 None 并且在 timeout 秒内仍然没有执行完得到结果,则抛出 multiprocessing.TimeoutError 异常。如果远程调用发生异常,这个异常会通过 get()重新抛出
wait([timeout])阻塞,直到返回结果,或者 timeout 秒后超时
ready()返回执行状态,是否已经完成。
successful()判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError
terminate()立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作,如果P(multiprocessing.Prosse)被回收,则自动调用此方法
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值