0 multiprocessing
multiprocessing是支持大量进程,类似于线程模块的API包.本包提供本地和远程并发,通过使用子进程而不是线程,可有效避免全局解释器锁的单步执行.因此,multiprocessing可充分利用机器上的多个处理器.
进程,是资源(CPU,内存)分配的基本单位
,是运行程序的一个实例,程序运行时系统会创建一个进程,并分配资源,然后将进程放入进程就绪队列,进程调度器选中他的时候会为其分配CPU资源,程序真正开始运行.
Linux系统,在父进程中创建子进程,当进程接受到客户端的请求是,可以复制出一个子进程来处理,父进程仅监控请求,然后创建子进程去处理,实现并发.
CPU的核数,表示可以同时执行的进程数,解析一下,CPU可以处理成千上万个进程,但是,CPU每个核每个时刻只能处理一个任务即进程,所以,多任务并行是指同一时刻可以执行的进程数量.
线程,是程序运行的基本单位
,是进程的一个执行流,是CPU调度和分配的基本单位,一个进程可由多个线程组成,线程间共享所有资源,每个线程有自己的堆栈和局部变量,线程有CPU独立调度执行,多CPU允许多个线程同时运行.
1 Pool
功能:进程池用于执行在pool类中提交的任务,即进程池用于控制发布任务的工作进程.支持超时和回调的异步结果,具有并行映射实现.进程池数量即为同时可执行的最大任务数量.
1.0 参数
Pool(process[,initializer[,initargs[,maxtasksperchild[,context]]]])
序号 | 参数 | 说明 |
---|---|---|
1 | processes | 使用的工作进程数量,若为None,返回os.cpu_count() 使用的cpu数量 |
2 | initializer | initializer不为None,每个工作进程启动时会调用initializer(*initargs) |
3 | intiargs | 进程方法的参数 |
4 | maxtasksperchild | 该参数是工作进程在退出并替换为新的工作进程之前处理的最大进程数量,用于释放未使用的资源 |
5 | context | 指定启动工作进程的上下文 |
1.2 方法
序号 | 方法 | 描述 |
---|---|---|
1 | close | 禁止任何任务进入进程池,当所有任务完成后工作进程退出 |
2 | terminate | 立即停止工作进程,不继续进行未完成的工作进程 |
3 | join | 等待工作进程退出,必须在close()或terminate()后使用,等待进程池中的所有子进程完成 |
4 | map | map()内置函数的平行函数 |
5 | apply_async | 以非阻塞方式执行池中的任务,可同时执行开辟的池个数任务量 |
6 | apply | 以阻塞方式执行池中任务,即执行返回结果后,开放进程池,其他任务进入,继续执行 |
1.3 测试
1.3.1 Demo1
from multiprocessing import Pool
# 执行函数
def f(x):
return x*x
if __name__ == "__main__":
# 进程池数量:5
with Pool(5) as p:
print(p.map(f, [1, 3, 4]))
[1, 9, 16]
1.3.2 Demo2
进程池个数与任务个数相同.
- pool_test.py
from multiprocessing import Pool
import os, time, random
def func_1():
#os.getpid()获取当前的进程的ID
print("\nRun task func_1, child process id: {}" .format(os.getpid()))
start = time.time()
time.sleep(5)
end = time.time()
print('Task fucn_1, runs {} seconds.'.format(end - start))
def func_2():
print("\nRun task func_2, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(5)
end=time.time()
print('Task func_2 runs {} seconds.'.format(end - start))
def func_3():
print("\nRun task func_3, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(5)
end = time.time()
print('Task func_3 runs {} seconds.'.format(end - start))
def func_4():
print("\nRun task func_4, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(10)
end = time.time()
print('Task func_4 runs {} seconds.'.format(end - start))
if __name__=='__main__':
function_list= [func_1, func_2, func_3, func_4]
print("Parent process id: {}".format(os.getpid()))
pool = Pool(4)
for func in function_list:
#Pool执行函数,apply执行函数,当有一个进程执行完毕后,会添加一个新的进程到pool中
pool.apply_async(func)
print('Waiting for all subprocesses done...')
# close()执行后不会有新的进程加入到pool
pool.close()
# join函数等待所有子进程结束
pool.join()
print ('All subprocesses done.')
- Result
Parent process id: 8592
Run task func_1, child process id: 9563
Run task func_3, child process id: 9565
Run task func_2, child process id: 9564
Run task func_4, child process id: 9566
Waiting for all subprocesses done...
Task func_3 runs 5.005031585693359 seconds.
Task fucn_1, runs 5.0050342082977295 seconds.
Task func_2 runs 5.003967046737671 seconds.
Task func_4 runs 10.02004051208496 seconds.
All subprocesses done.
- Analysis
(1) 进程池中进程最大数为4,即同时可运行4个程序或函数;
(2) 将4个函数放入进程池,使用apply_async
实现非阻塞,即可同时运行4个函数,从前三个的延迟时间都设为5可看出,基本同时输出结果;
1.3.3 Demo3
进程池进程数量小于任务个数.
- pool_test.py
from multiprocessing import Pool
import os, time, random
def func_1():
#os.getpid()获取当前的进程的ID
print("\nRun task func_1, child process id: {}" .format(os.getpid()))
start = time.time()
time.sleep(5)
end = time.time()
print('Task fucn_1, runs {} seconds.'.format(end - start))
def func_2():
print("\nRun task func_2, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(5)
end=time.time()
print('Task func_2 runs {} seconds.'.format(end - start))
def func_3():
print("\nRun task func_3, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(5)
end = time.time()
print('Task func_3 runs {} seconds.'.format(end - start))
def func_4():
print("\nRun task func_4, child process id: {}".format(os.getpid()))
start = time.time()
time.sleep(10)
end = time.time()
print('Task func_4 runs {} seconds.'.format(end - start))
if __name__=='__main__':
function_list= [func_1, func_2, func_3, func_4]
print("Parent process id: {}".format(os.getpid()))
pool = Pool(2)
for func in function_list:
#Pool执行函数,apply执行函数,当有一个进程执行完毕后,会添加一个新的进程到pool中
pool.apply_async(func)
print('Waiting for all subprocesses done...')
# close()执行后不会有新的进程加入到pool
pool.close()
# join函数等待所有子进程结束
pool.join()
print ('All subprocesses done.')
- Result
Parent process id: 8592
Run task func_1, child process id: 10639
Run task func_2, child process id: 10640
Waiting for all subprocesses done...
Task fucn_1, runs 5.004624843597412 seconds.
Task func_2 runs 5.002416610717773 seconds.
Run task func_3, child process id: 10639
Run task func_4, child process id: 10640
Task func_3 runs 5.005084991455078 seconds.
Task func_4 runs 10.010075330734253 seconds.
All subprocesses done.
- Analysis
(1) 进程池进程数量为2,任务量为4,即同时执行2个任务,当执行完成一个任务之后,释放资源,并将另一个任务放入进程池;
(2) close用于控制进程池的开关,即保证线程池内的任务顺利执行,而不被其他未加入进程池的任务打断;
(3) join保证了进程池中任务的子进程正常进行,即进程池中的任务包含的子进程全部完成后,才最终退出,即上面结果中的时间输出,当所有时间输出后,进程任务结束;
2 Pipe
2.1 功能
返回一对表示管道末端的连接对象(conn1, conn2),进程间的管道内部机制通过启动socket连接来保持进程间的通讯.
2.2 参数
Pipe([duplex])
duplex为True(默认),pipe是双向的,若为False,pipe为单向的,conn1只能接受消息,conn2只能发送消息;
2.3 Demo
from multiprocessing import Process, Pipe
def server_process(con):
# 向客户端进程发送数据
con.send("xin")
# 接受客户端进程数据
print("From father process: {}".format(con.recv()))
if __name__ == "__main__":
# 实例化管道Pipe,建立socket连接
# 服务端和客户端,conn1,conn2
server, client = Pipe()
# 开始服务端进程
p = Process(target=server_process, args=(server, ))
p.start()
# 客户端接受服务端进程数据
client_process = client.recv()
print("Received server data: {}".format(client_process))
client.send("daqi")
Received server data: xin
From father process: daqi
3 Queue
3.1 功能
返回使用pipe和lock/semaphores实现的共享队列进程,用于进程间通信.先进先出(First Input First Output, FIFO);当一个进程将一个项目放入队列时,会启动一个feeder线程,该线程将对象从缓冲区传送到pipe中.
3.2 参数
Queue(maxsize=0)
参数 | 描述 |
---|---|
maxsize | 整数,设置可放入队列的项目数上限.数据填满队列后,进入阻塞,知道队列内容取出.若maxsize小于等于0,队列数目无限制. |
3.3 方法
序号 | 参数 | 描述 |
---|---|---|
1 | qsize() | 返回队列数量的近似值 |
2 | empty() | 若队列为空,返回True |
3 | full() | 队列全部占满,返回True |
4 | put(obj[,block[,timeout]]) | 将obj放入队列,若block为True(默认),timeout=None(默认),队列中无空闲位置时会阻塞,若timeout为正数,阻塞时间最长为timeout秒,若仍无空闲位置,则会调用queue.Full |
5 | get([block[,timeout]]) | 从队列获取对象并移除该对象,若block为True(默认),timeout=None(默认),队列中无空闲位置时会阻塞,若timeout为正数,阻塞时间最长为timeout秒,若阻塞结束后仍不能去除对象,则会调用queue.Empty |
3.4 Demo1
from multiprocessing import Queue, Process
# 数据进队列
def queue_test(que):
que.put("xindaqi")
if __name__ == "__main__":
# 建立队列,10个卡位
Q = Queue(10)
# 建立进程,将队列作为参数,传入队列操作函数
p = Process(target=queue_test, args=(Q, ))
p.start()
p.join()
print("Queue data: {}".format(Q.get()))
Queue data: xindaqi
3.5 Demo2
from multiprocessing import Queue, Pool
import time
def queue_test(q):
# 数据入队列
for i in range(2):
q.put(i)
# 取出队列数据
q_output = q.get()
print("Queue data: {}".format(q_output))
if __name__ == "__main__":
Q = Queue(10)
start_time = time.time()
# 建立3个线程,同时执行3个任务
pool = Pool(3, queue_test, (Q, ))
pool.terminate()
end_time = time.time()
cost_time = end_time - start_time
print("Cost time: {}".format(cost_time))
Queue data: 0
Queue data: 0
Queue data: 1
Queue data: 0
Queue data: 1
Queue data: 1
Cost time: 0.11123538017272949
4 Process
4.1 功能
表示在运行的独立进程,进程类拥有所有threading.Thread
方法.
4.2 参数
Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
序号 | 参数 | 描述 |
---|---|---|
1 | group | 设定为None,作用只是为了和threading.Thread兼容 |
2 | target | run()方法调用的可执行对象,如函数 |
3 | name | 进程名称 |
4 | args | tuple类型的参数 |
5 | kwargs | dict类型的参数 |
6 | daemon | 进程标志为,若为None(默认为None),该标志从创建的进程中继承 |
4.3 方法
序号 | 方法 | 描述 |
---|---|---|
1 | run() | 表示进程活动的方法 |
2 | start() | 开启进程 |
3 | join([timeout]) | 默认timeout=None,结束前(terminate),进程是阻塞的,若timeout为正数,表示最大的阻塞时长(秒) |
4 | name | 进程名称 |
5 | is_alive() | 返回进程是否活动 |
6 | daemon | 进程守护标志,在start()前使用 |
7 | pid | 返回进程ID,在start()之后,即启动进程后,才有ID,否则返回None |
8 | terminate() | 结束进程 |
9 | kill() | 杀死进程,类似terminate,只能在Unix |
10 | close() | 关闭进程,释放资源 |
4.4 Demo
from multiprocessing import Process
import os
def info(title):
print("Title: {}".format(title))
print("module name: {}".format(__name__))
print("Parent process: {}".format(os.getppid()))
print("Subprocess id: {}".format(os.getpid()))
def f(name):
info("function f")
print("Hello {}".format(name))
if __name__ == "__main__":
info("Main line")
print("==================")
p = Process(target=f, args=('xindaqi',))
p.start()
p.join()
Title: Main line
module name: __main__
Parent process: 29719
Process id: 29755
==================
Title: function f
module name: __main__
Parent process: 29755
Process id: 17714
Hello xindaqi
[参考文献]
[1]https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool
[2]https://www.cnblogs.com/zhehan54/p/6130030.html
[3]http://www.cnblogs.com/wdliu/p/6828070.html
[4]https://www.cnblogs.com/kaituorensheng/p/4465768.html