45_并发编程-进程池

一、为什么引入进程池

在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程(空间,变量,文件信息等等的内容)也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,维护一个很大的进程列表的同时,调度的时候,还需要进行切换并且记录每个进程的执行节点,也就是记录上下文(各种变量等等乱七八糟的东西,虽然你看不到,但是操作系统都要做),这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。就看我们上面的一些代码例子,你会发现有些程序是不是执行的时候比较慢才出结果,就是这个原因,那么我们要怎么做呢?

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

二、multiprocessing 引入Pool 模块

1 1、语法格式:Pool([numprocess [,initializer [, initargs]]]):创建进程池
2         numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值
3         initializer:是每个工作进程启动时要执行的可调用对象,默认为None
4         initargs:是要传给initializer的参数组

创建进程池的类:如果指定numprocess为3,则进程池会从无到有创建三个进程,然后自始至终使用这三个进程去执行所有任务(高级一些的进程池可以根据你的并发量,搞成动态增加或减少进程池中的进程数量的操作),不会开启其他进程,提高操作系统效率,减少空间的占用等。numprocess不行会选择cpu分配,1  -> processes = os.cpu_count() or 1

2、主要方法

 1 <1> map()  - 并且自带close和join,一般约定俗成的是进程池中的进程数量为CPU的数量,工作中要看具体情况来考量。
 2
 3 # 进程池与进程的时间比较
 4
 5 import time
 6 from multiprocessing import Process, Pool
 7
 8 def func(n):
 9     print(n)
10
11 if __name__ == ‘__main__‘:
12
13     # 进程池运行时间
14     time_pool_start = time.time()
15     pool =Pool(4)   # 进程池中只放4个进程
16     pool.map(func, range(100))      # 使用map方法实现,map实现的是异步的。map参数可迭代 range(100),把可迭代的元素放入func中执行
17     time_pool_end = time.time()
18     p_dif = time_pool_end - time_pool_start
19
20     # 进程运行时间
21     time_pro_start = time.time()
22     lst = []
23     for i in range(100):
24         p = Process(target=func, args=(i,))
25         p.start()
26         lst.append(p)
27     [obj.join() for obj in lst]
28     time_pro_end = time.time()
29     p_dif_pro = time_pro_end - time_pro_start
30
31     print("进程池>>",p_dif)
32     print("进程>>", p_dif_pro)
 1 <2> apply()       -        apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。同步执行,一个一个出,它会等待任务的执行结果
 2                    需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用
 3
 4 import time
 5 from multiprocessing import Process,Pool
 6
 7 def fun(i):
 8     time.sleep(0.5)
 9     # print(i)
10     return i**2
11
12 if __name__ == ‘__main__‘:
13     p = Pool(4)
14     for i in range(10):
15         res = p.apply(fun,args=(i,))  #同步执行的方法,他会等待你的任务的返回结果,
16         print(res)
 1 <3> apply_async()    -   apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果; 异步的
 2                         此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。
 3
 4 import time
 5 from multiprocessing import Pool
 6
 7 def func(n):
 8     time.sleep(0.5)
 9     return n**2
10
11 if __name__ == ‘__main__‘:
12
13     p = Pool(4)
14     lst = []    # 设置一个空列表
15     for i in range(10):
16         ret = p.apply_async(func, args=(i,))  # 异步步执行,获取返回值
17         lst.append(ret)     # 异步的,返回值放一个列表
18     time.sleep(1)
19     for el in lst:  # 循环列表
20         print(el.get()) # 获取异步结果,因为get()一次只能取一个值,使用进程池取数据,每4个一组一打
21
22 ----------------------------------------------------------------------------------------
23 import time
24 from multiprocessing import Pool
25
26 def func(n):
27     time.sleep(0.5)
28     print(n)
29     return n**2
30
31 if __name__ == ‘__main__‘:
32
33     p = Pool(4)
34     lst = []    # 设置一个空列表
35     for i in range(10):
36         ret = p.apply_async(func, args=(i,))  # 异步步执行,获取返回值,4个一组
37         lst.append(ret)     # 异步的每4个放一个列表
38
39     p.close() # 不是关闭进程池,而是不允许再有其他任务来使用进程池
40     p.join()    # 这是感知进程池中任务的方法,等待进程池的任务全部执行完
41
42     for el in lst:  # 循环列表,这样把进程池关上,不允许别的任务用,就会全部打印出来
43         print(el.get()) # 获取异步结果,因为get()一次只能取一个值
44     print(‘主进程‘)

3、回调函数 - callback

需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数,这是进程池特有的,普通进程没有这个机制,但是我们也可以通过进程通信来拿到返回值,进程池的这个回调也是进程通信的机制完成的。

我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果

 1 import os
 2 from multiprocessing import Pool
 3
 4 def func1(n):
 5     print(‘func1>>‘,os.getpid())
 6     # print(‘func1‘)
 7     return n*n
 8
 9
10 def func2(nn):
11     print(‘func2>>‘,os.getpid())
12     # print(‘func2‘)
13     print(nn)
14     # import time
15     # time.sleep(0.5)
16 if __name__ == ‘__main__‘:
17     print(‘主进程:‘,os.getpid())
18     p = Pool(4)
19     p.apply_async(func1,args=(10,),callback=func2)    # func1->子进程运行; func2->主进程运行,把func1返回的值给func2去执行其他操作
20     p.close()
21     p.join()

原文地址:https://www.cnblogs.com/hq82/p/9851654.html

时间: 2024-12-10 15:07:32

45_并发编程-进程池的相关文章

(并发编程)进程池线程池--提交任务的2种方式、协程--yield greenlet,gevent模块

一:进程池与线程池(同步,异步+回调函数)先造个池子,然后放任务为什么要用"池":池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务池子内什么时候装进程:并发的任务属于计算密集型池子内什么时候装线程:并发的任务属于IO密集型 #提交任务的两种方式:    # 同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行的    # 异步调用:提交完一个任务之后,不在原地等待,结果???,而是

Python并发编程-进程池

为什么有进程池的概念 效率问题 每次开启进程,都需要开启属于这个进程的内存空间 寄存器,堆栈 进程过多,操作系统的调度 进程池 python中的 先创建一个属于进程的池子 这个池子指定能存放多少进程 先将这些进程创建好 更高级的进程池 3,20 默认启动3个进程 处理能力不够的时候,加进程 最多20个 python中没有 from multiprocessing import Pool,Process import time #Process就无需使用了 def func(n): for i i

Python并发编程—进程池

进程池实现 1.必要性[1] 进程的创建和销毁过程消耗的资源较多[2] 当任务量众多,每个任务在很短时间内完成时,需要频繁的创建和销毁进程.此时对计算机压力较大[3] 进程池技术很好的解决了以上问题. 2.原理 创建一定数量的进程来处理事件,事件处理完进 程不退出而是继续处理其他事件,直到所有事件全都处理完毕统一销毁.增加进程的重复利用,降低资源消耗. 3.进程池实现 [1] 创建进程池对象,放入适当的进程 from multiprocessing import Pool Pool(proces

python_并发编程——进程池

1.进程池 from multiprocessing import Pool def func(n): for i in range(10): print(n+1) if __name__ == '__main__': pool = Pool(3) #启动有三个进程的进程池. #第一个参数进程要访问的代码,第二个参数必须是一个可迭代参数,规定了要执行的任务数 pool.map(func,range(100)) #100个任务 结果: 每个数打印了10次. 2.进程池和多进程的用时对比 def f

Linux高性能服务器编程——进程池和线程池

进程池和线程池 池的概念 由于服务器的硬件资源"充裕",那么提高服务器性能的一个很直接的方法就是以空间换时间,即"浪费"服务器的硬件资源,以换取其运行效率.这就是池的概念.池是一组资源的集合,这组资源在服务器启动之初就完全被创建并初始化,这称为静态资源分配.当服务器进入正是运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配.很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因为分配系统资源的系统调用都是很耗时的.当

17.并发编程--线程池

并发编程线程池 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立即执行. 第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 1. Executor 框架简介 在 Java 5 之后,并发编程引入了一堆新的启动.调度和管理 线

Linux网络编程——进程池实现过程详解(1)

目录 进程池 父进程的实现流程 子进程的实现流程 进程池 父进程的实现流程 1.定义数据结构pChild,申请子进程数目的结构体空间 2.通过循环,socketpair创建全双工管道,创建子进程,将子进程pid,管道对端,是否忙碌等信息存储 3.socket,bind,listen,对应的端口处于监听状态 netstat 4.epoll_create创建epfd,监控socketFd和所有子进程的管道对端 5.while(1)循环 epoll_wait等待客户端的请求及子进程是否有通知 如果so

并发编程--线程池与进程池

核心思想 以时间换空间 进程池 进程池:一个容器,这个容器限制住你开启进程的数量,默认是os.cpu_count(),我的电脑是8核,所以能开启8个,第一次肯定只能并行的处理8个任务,只要有任务完成,进程马上就会接下一个任务. 代码实现: from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os,time,random # print(os.cpu_count()) def task(n): p

并发编程 进程基础

操作系统 多道 .分时.实时 同步异步 同步:一件事情完成后再做另一件事 异步:同时做多件事 阻塞和非阻塞 阻塞:recv,accept,recvfrom 会让整个进程进入阻塞队列 非阻塞:进程只会在就绪和 运行状态中切换 进程三状态:就绪 运行 阻塞 并发并行 并发是包含并行的 并发:宏观上多个程序同时运行,实际是同一时间只运运行了一次 并行:微观上多个程序同时运行 子进程和主进程 pid ppid 多并发的tcp服务端 import socket from multiprocessing i