进程理论知识
进程就是正在运行的程序,是计算机进行资源分配的最小单位。
各个进程都有独立的数据,相互隔离
Linux里进程的状态
- R 运行状态runable
- S 中断睡眠态(TASK_INTERRUPTIBLE)
- D 不可中断睡眠态(TASK_UNINTERRUPTIBLE)
- Z 僵尸态:(TASK_ZOMBIE)
- T/t 停止态(TASK_STOPPED)
所有进程都是由另外一个进程创建的。父进程 ---- 子进程
僵尸进程: 子进程退出时,父进程没有响应,即父进程没有调用wait()或者waitpid()去获取子进程的状态、 子进程的进程控制块就会依然保存在系统中,这种进程称之为僵尸进程。
孤儿进程: 父进程退出,子进程还在运行,那么子进程就是孤儿进程。孤儿进程会被pid为1的进程所收养。
multiprocessing模块实现多进程
multiprocessing包是Python中的多进程管理包。
与threading.Thread类似、 multiprocessing 模块使用Process创建进程、该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法(参考我的上一篇多线程文章)
Process构造方法:Process(group=None, target=None, name=None, args=(), kwargs={})
- group: 线程组,目前还没有实现,库引用中提示必须是None;
- target: 要执行的方法;
- name: 线程名;
- args/kwargs: 要传入方法的参数、args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号;
属性介绍:
- t.name:获取或设置进程的名称
- t.pid:获取进程的pid
- t.is_alive()/t.isAlive():判断进程是否为激活状态。如果t仍然运行,返回True
- t.run():进程被cpu调度后自动执行进程对象的run方法 ,run方法会调用传入的target方法
- t.start(): 进程准备就绪,等待CPU调度,start会自动调用t.run()。
- t.join([timeout]):
阻塞当前上下文环境的进程,直到调用此方法的进程终止或到达指定的timeout (可选参数)
。
- t.setDaemon(): 设置为后台进程,主进程退出子进程也退出。默认为前台进程(False),主进程执行完了,等子进程执行完再退出)。
from multiprocessing import Process, current_process
import time
lst = []
def task(i):
print(current_process().name, i, 'start...') # current_process().name输出进程的名字
time.sleep(2)
lst.append(i)
print(lst)
print(current_process().name, i, 'end.....')
if __name__ == "__main__":
p_lst = []
for i in range(4):
p = Process(target=task, args=(i,))
p_lst.append(p)
p.start()
for p in p_lst:
p.join() # 阻塞当前进程,直到子进程全部退出
print("main end.......")
使用多进程需要注意:必须使用if __name__ == "__main__":
,表示只有直接调用当前模块时(即主程序)name才等于main,如果该程序是被当作模块导入,则不会执行。
进程池
进程池采用预创建的技术、在应用启动之初便预先创建一定数目的进程
python中使用 multiprocessing.Pool创建一个进程池
示例: p = Pool(processes=4, maxtasksperchild=3)
processes=4 表示进程池内4个子进程,建议进程数与CPU核数一致。另外还有主进程管理他们,kill掉一个子进程后又会自动启动一个
maxtasksperchild=3 表示每一个进程最多处理3个任务,然后该进程就结束,主进程会再开启新的进程去处理剩下的任务、释放已完成任务的内存空间。
from multiprocessing import Pool, current_process
import time
lst = []
def task(i):
print(current_process().name, i, 'start...')
time.sleep(2)
lst.append(i)
print(lst)
print(current_process().name, i, 'end.....')
if __name__ == "__main__":
p = Pool(processes=4, maxtasksperchild=3)
for i in range(20):
p.apply_async(func=task, args=(i,)) # 进程池接收任务
p.close() # 关闭进程池 ==》 不接受任务
p.join() # 等待子进程执行完毕,父进程再执行
print("end.............")
运行结果展示
这里我们可以看出、首先SpawnPoolWorker-1、SpawnPoolWorker-2、SpawnPoolWorker-3、SpawnPoolWorker-4 这4个进程都会分别去获取任务并执行,当执行了3个任务后、我们发现进程池内的程序变成了SpawnPoolWorker-5、SpawnPoolWorker-6、SpawnPoolWorker-7、SpawnPoolWorker-8,而前4个进程则被释放掉了。
D:\softs\python\python.exe E:/project/sanchuang/python基础/多进程多线程协程/code_进程池.py
SpawnPoolWorker-1 0 start...
SpawnPoolWorker-2 1 start...
SpawnPoolWorker-3 2 start...
SpawnPoolWorker-4 3 start...
[0]
SpawnPoolWorker-1 0 end.....
SpawnPoolWorker-1 4 start...
[2]
[1]
SpawnPoolWorker-3 2 end.....
SpawnPoolWorker-2 1 end.....
SpawnPoolWorker-2 5 start...
SpawnPoolWorker-3 6 start...
[3]
SpawnPoolWorker-4 3 end.....
SpawnPoolWorker-4 7 start...
[0, 4]
SpawnPoolWorker-1 4 end.....
SpawnPoolWorker-1 8 start...
[1, 5]
[2, 6]
SpawnPoolWorker-2 5 end.....
SpawnPoolWorker-3 6 end.....
SpawnPoolWorker-3 9 start...
SpawnPoolWorker-2 10 start...
[3, 7]
SpawnPoolWorker-4 7 end.....
SpawnPoolWorker-4 11 start...
[0, 4, 8]
SpawnPoolWorker-1 8 end.....
[2, 6, 9]
SpawnPoolWorker-3 9 end.....
[1, 5, 10]
SpawnPoolWorker-2 10 end.....
[3, 7, 11]
SpawnPoolWorker-4 11 end.....
SpawnPoolWorker-5 12 start...
SpawnPoolWorker-6 13 start...
SpawnPoolWorker-7 14 start...
SpawnPoolWorker-8 15 start...
[12]
SpawnPoolWorker-5 12 end.....
SpawnPoolWorker-5 16 start...
[13]
SpawnPoolWorker-6 13 end.....
SpawnPoolWorker-6 17 start...
[14]
SpawnPoolWorker-7 14 end.....
SpawnPoolWorker-7 18 start...
[15]
SpawnPoolWorker-8 15 end.....
SpawnPoolWorker-8 19 start...
[13, 17]
[12, 16]
SpawnPoolWorker-6 17 end.....
SpawnPoolWorker-5 16 end.....
[14, 18]
SpawnPoolWorker-7 18 end.....
[15, 19]
SpawnPoolWorker-8 19 end.....
end.............
Process finished with exit code 0