进程池
为什么要有进程池
在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程
进程池的概念。
定义一个进程池,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果
设置进程池class multiprocessing.pool.Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
一个进程池对象,它控制可以提交作业的工作进程池
它支持带有超时和回调的异步结果,以及一个并行的 map 实现
参数 | 说明 |
---|---|
processes | 使用的工作进程数目。如果 processes 为 None ,则使用 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 极大 地加快执行速度。同样,如果chunksize 是 1 , 那么 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_sync
和multiprocessing.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 | 使用的工作进程数目。如果 processes 为 None ,则使用 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 极大 地加快执行速度。同样,如果chunksize 是 1 , 那么 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_sync
和multiprocessing.pool.map_async
返回对象
multiprocessing.pool.AsyncResult
的方法
函数 | 说明 |
---|---|
get ([timeout]) | 用于获取执行结果.如果 timeout 不是 None 并且在 timeout 秒内仍然没有执行完得到结果,则抛出 multiprocessing.TimeoutError 异常。如果远程调用发生异常,这个异常会通过 get()重新抛出 |
wait ([timeout]) | 阻塞,直到返回结果,或者 timeout 秒后超时 |
ready () | 返回执行状态,是否已经完成。 |
successful () | 判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError |
terminate() | 立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作,如果P(multiprocessing.Prosse )被回收,则自动调用此方法 |