进程&进程池
进程
服务器中, s.listen(n) n不能无限大,以为内存不可能无限大,n表示内存同一时间接纳的等待连接数,可以看成一个(队列),取出一个拿去建立连接,然后再放进一个,队列中一直保持n个连接
请求.
补充一点:
print() 是计算操作, 计算机中除了IO,都是计算(PS:cpu干的活都是计算).
进程的运行回收机制: 主进程等子进程运行完 才回收子进程,自己再关闭
父进程杀死了,子进程就会变成孤儿进程(甚至变成僵尸进程)
非常重要的一个概念:
运行py文件,在进程中显示的不是xx.py, 而是解释器的python.exe,
是因为代码只是一堆符号,没有意义,只有把代码传给python解释器,python解释器解释后,调用的python解释器的功能.
实际上用的python解释器的功能,所以进程中显示运行的是python.exe解释器而不是xx.py文件.
(举个例子:py文件中一行代码为print,那么python解释器就会调用自己的打印功能)
查看进程号:
import os print(os.getpid()) #打印进程id号 print(os.getppid()) # 父进程id号
查看进程和杀死进程:
cmd解释器中: tasklist |findstr python #管道符 过滤 查看python关键字 进程 干掉python进程 tskill python tskill 进程name tskill 进程pid号
运行环境的父进程:
运行一个xxx.py (python3环境下) , 打印这个进程的父进程id号,发现是pycharm 的id号.为什么呢? pycharm 运行 python3 xxx.py , 然后 产生一个 python.exe 进程.所以pycharm是这个python.exe的父进程 (pycharm 运行 python3 xxx.py ====>> python.exe) PS:如果在cmd中运行,这个python.exe的父进程就是cmd的id号
jion():
jion(),主进程等待子进程
import time from multiprocessing import Process def task(name): time.sleep(2) print('%s' % name) if __name__ == '__main__': p = Process(target=task,args=('kitty',)) p.start() p.join() #等 子进程运行完毕,主进程才继续往下运行 print('主进程')
如果有多个子进程:p1 p2 p3
p1.start() p1.join() p2.start() p2.join() p3.start() p3.join() # 这种情况下,相当于串行(等待上一个进程执行完,才继续往下执行下一个进程)
-
p1.start() p2.start() p3.start() p1.join() p2.join() p3.join() # 这种情况下,是并发(PS:join()的顺序先后没关系)
可以简洁点:
p_l = [p1,p2,p3] for p in p_l: p.start() for p in p_l: p.join()
name = None
进程名可以自定义:
if __name__ == '__main__': p = Process(target=task,args=('kitty',),name='haha') p.start() p.join() print(p.name) #haha 自定义子进程名字 print('主进程')
terminate(): 杀死进程
is_alive(): 判断进程是否活着
def task(name): time.sleep(2) print('%s' % name) if __name__ == '__main__': p = Process(target=task,args=('kitty',)) p.start() p.terminate() #杀死进程p print(p.is_alive()) #True 之所以是True,而不是False,是因为杀死进程p.terminate()只是发了一个信号,主进程马上就判断 # (杀死进程需 要时间) print('主进程')
注意:
慎用, 如果儿子进程开了个孙子进程,就会产生孤儿进程(比较危险)
现实场景也很少这种操作
进程池
1.进程池中存放的就是进程,只不过加上了数目的限制,
2.进程池造出来后,不会开新的进程,从始至终就是造进程池时定义的数目
3.等进程池中的所有进程都完毕,先关门,在等(shutdown(wait = True))
示例:
import time from concurrent.futures import ProcessPoolExecutor def task(name): time.sleep(2) print('%s' % name) if __name__ == '__main__': p = ProcessPoolExecutor(4) # 立刻造好4个进程 # p.submit(task,'kitty1') # p.submit(task,'kitty2') # p.submit(task,'kitty3') # p.submit(task,'kitty4') for i in range(1, 11): p.submit(task, 'kitty%s' % i) #submit() 往里面丢任务 print('主进程')
提交/调用 任务的方式
1.同步调用:
提交/调用一个任务,然后就在原地等着,等到该任务执行完毕拿到结果,再执行下一行代码
2.异步调用:
提交/调用一个任务,不在原地等着,直接执行下一行代码.
from concurrent.futures import ProcessPoolExecutor
新版本中(新模块中)根本就没有同步接口,只有异步接口,就是submit()
新版本中:
关门+等
shutdown(wait = True)
---------------------------------------------------------------------------------------
from multiprocessing import Process, Pool
老版本中(Pool)中有个同步接口 p.apply()
老版本中:
关门+等
pool.close()
pool.join()
--------------------------------------------------------
同步调用方式:
开进程 等待 再开,再等这种提交任务的方式,想当于串行
for p in p_l: p.start() p.join()
示例:
import time from concurrent.futures import ProcessPoolExecutor def task(name, n): time.sleep(1) print('%s' % name) return n**2 if __name__ == '__main__': p = ProcessPoolExecutor(4) p_l = [] for i in range(1, 11): obj = p.submit(task, 'kitty%s' % i, i) print(obj.result()) #相当于start和join连用 print('主进程') # kitty1 # 1 # kitty2 # 4 # kitty3 # 9 # kitty4 # 16 # kitty5 # 25 # kitty6 # 36 # kitty7 # 49 # kitty8 # 64 # kitty9 # 81 # kitty10 # 100 # 主进程
异步调用方式:
for i in range(10): p.submit(func,'xx')
示例:
import time from concurrent.futures import ProcessPoolExecutor def task(name, n): time.sleep(1) print('%s' % name) return n**2 if __name__ == '__main__': p = ProcessPoolExecutor(4) p_l = [] for i in range(1, 11): obj = p.submit(task, 'kitty%s' % i, i) # obj是个对象,通过对象拿到结果 p_l.append(obj) p.shutdown(wait = True) #shutdown(wait = True) 等,但是前提是进程池中不能再放进新的任务了,否则数目不准确(先关门+等) print('主进程') for i in p_l: print(i.result()) # kitty1 # kitty2 # kitty3 # kitty4 # kitty5 # kitty6 # kitty7 # kitty8 # kitty9 # kitty10 # 主进程 # 1 # 4 # 9 # 16 # 25 # 36 # 49 # 64 # 81 # 100