Python之路PythonThread,第二篇,进程2
python3 进程2
僵尸进程处理方法:
3,创建二级子进程处理
4,在父进程中使用信号处理的方法忽略子进程发来的信号;
signal(SIGCHLD,DIG,IGN)
1 # 创建二级子进场解决僵尸进程 2 import os 3 4 #创建一级子进程 5 pid = os.fork() 6 7 if pid < 0: 8 print('create process failed') 9 elif pid == 0: 10 #创建二级子进程 11 p = os.fork() 12 if p < 0: 13 print('process failed') 14 elif p == 0: 15 print("做二级子进程任务") 16 else: 17 #一级子进程退出,使二级子进程成为孤儿 18 os._exit(0) 19 else: 20 #等待一级子进程退出 21 os.wait() 22 print("做父进程该做的")
更高效的进程创建方法
multiprocessing 模块(标准库模块)
创建的进程的步骤:
1,将要完成的事件封装成一个个函数;
2,使用multiprocessing提供的接口函数创建进程;
3,使新的进程和指定的函数相关联去完成函数中的工作;
4,对进程进行回收处理;
1 import multiprocessing as mp 2 import os 3 import time 4 5 #将要做的事封装为函数 6 def th1(): 7 print(os.getppid(),"----",os.getpid()) 8 print('吃饭早饭') 9 time.sleep(1) 10 print('吃饭午饭') 11 time.sleep(2) 12 print('吃饭晚饭') 13 time.sleep(3) 14 15 def th2(): 16 print(os.getppid(),"----",os.getpid()) 17 print("睡午觉") 18 time.sleep(1) 19 print("睡觉") 20 time.sleep(3) 21 22 def th3(): 23 print(os.getppid(),"----",os.getpid()) 24 print("打豆豆") 25 time.sleep(2) 26 print("打豆豆") 27 time.sleep(2) 28 29 #创建3个子进程,生成子进程对象 30 #将函数和进程进行关联 31 p1 = mp.Process(target = th1) 32 p2 = mp.Process(target = th2) 33 p3 = mp.Process(target = th3) 34 35 #启动进程让其执行对应的函数事件 36 #该函数即为这个就进程内容 37 p1.start() 38 p2.start() 39 p3.start() 40 41 print("Parent PID:",os.getpid()) 42 43 # 阻塞等对应子进程的退出,然后回收子进程 44 p1.join() 45 p2.join() 46 p3.join() 47 48 print("***********************") 49 # th1() 50 # th2() 51 # th3()
注:1,函数当付给Process的target比那里后函数内容就是对应进程的进程内容,此时函数才有特殊性;
2,多个子进程和父进程之间的执行相互不影响;
创建子进程:
Process() 类
参数: target指定要绑定的函数;
name 给创建的进程起一个名字;
args 需要一个元组,给target指定的函数按位置传参;
kwargs 需要一个字典,给target指定的函数按键值传参;
#进程函数的使用 from multiprocessing import Process from time import sleep def worker(sec): for i in range(3): sleep(sec) print("the worker xiaoming") p = Process(name = 'worker',\ target = worker,args = (2,),\ kwargs = {}) p.start() p.join()
1 #进程函数的使用 2 from multiprocessing import Process 3 from time import sleep 4 5 def worker(sec,msg): 6 for i in range(3): 7 sleep(sec) 8 print("the worker msg",msg) 9 10 p = Process(name = 'worker',\ 11 target = worker,args = (2,),\ 12 kwargs = {'msg':'You are a big man'}) 13 14 p.start() 15 16 p.join()
1 #进程函数的使用 2 from multiprocessing import Process 3 from time import sleep 4 5 a = 1 6 7 def worker(sec,msg): 8 #当worker作为子进程运行时,对全局量a 的修改只会 9 #影响在子进程中a的值 ,对父进程没有影响 10 global a 11 a = 1000 12 for i in range(3): 13 sleep(sec) 14 print("the worker msg",msg) 15 print(a) 16 17 p = Process(name = 'worker',\ 18 target = worker,args = (2,),\ 19 kwargs = {'msg':'You are a big man'}) 20 21 p.start() 22 23 p.join() 24 25 ##### 26 a=1000
1 #进程函数的使用 2 from multiprocessing import Process 3 from time import sleep 4 5 a = 1 6 7 def worker(sec,msg): 8 #当worker作为子进程运行时,对全局量a 的修改只会 9 #影响在子进程中a的值 ,对父进程没有影响 10 global a 11 a = 1000 12 for i in range(3): 13 sleep(sec) 14 print("the worker msg",msg) 15 print(a) 16 17 p = Process(name = 'worker',\ 18 target = worker,args = (2,),\ 19 kwargs = {'msg':'You are a big man'}) 20 21 p.start() 22 23 #进程名称 24 print("进程名称:",p.name) 25 print("进程PID:",p.pid) 26 print('进程状态:',p.is_alive()) 27 28 p.join() 29 print('parent:',a)
Process() 类 ---->进程对象
属性方法:
print("进程名称", p.name)
print('进程PID',p.pid)
print('进程状态',p.is_alive())
启动子进程
start()
注:start() 时才真正的创建子进程,而不是Process时创建;
回收子进程
join(timeout)
timeout : 设置最长阻塞时间,如果超过这个时间还没有子进程退出,则不再继续等待;
注:内核会帮助应用层记录子进程的退出情况,当使用join函数时,内核会及时返回进程状态给应用层进行处理;
1 import multiprocessing as mp 2 import os 3 import time 4 5 def th1(): 6 print(os.getppid(),"----",os.getpid()) 7 print('吃饭早饭') 8 time.sleep(1) 9 print('吃饭午饭') 10 time.sleep(6) 11 print('吃饭晚饭') 12 time.sleep(3) 13 14 def th2(): 15 print(os.getppid(),"----",os.getpid()) 16 print("睡午觉") 17 time.sleep(3) 18 print("睡觉") 19 time.sleep(3) 20 21 def th3(): 22 print(os.getppid(),"----",os.getpid()) 23 print("打豆豆") 24 time.sleep(5) 25 print("打豆豆") 26 time.sleep(2) 27 28 things = [th1,th2,th3] 29 process = [] 30 31 for th in things: 32 p = mp.Process(target = th) 33 process.append(p) 34 35 for p in process: 36 p.start() 37 38 for i in process: 39 i.join(1) 40 41 print("++++++++++++++++++")
p.daemon
默认值为False,表示主进程运行结束后,不会影响子进程的运行,直到子进程运行完,进程才会结束;
如果设置为True, 则主进程运行完毕,则所有子进程也不再运行一起推出;
注:1,该属性的设置必须要在start前
2,该属性的设置并不是讲进程设置为linux、unix中的守护进程;
守护进程: 生命周期长,与前端控制台无关,后台运行,一般用做系统进程或自动化运行进程;
多进程编程:
优点:1,可以并行的执行多个任务,提高运行效率;
2,空间独立,数据方便;
3,创建方便;
缺点:进程的创建和销毁过程需要消耗较多的计算资源;
在需要频繁的创建和删除较多进程的情况下,资源消耗过多,不适宜使用多进程完成任务;
进程池技术:
1,创建进程池,在池内放入合适数量的进程;
2,将时间加入进程池的等待队列;
3,使用进程池内的进程不断的执行等待事件;
4,所有事件处理结束后关闭回收进程池;
1 #!/usr/bin/python3 2 3 import multiprocessing as mp 4 from time import sleep 5 import os 6 7 def worker(msg): 8 sleep(2) 9 print(msg) 10 11 #创建进程池对象,进程池中包含4个进程 12 pool = mp.Pool(processes = 4) 13 14 for i in range(10): 15 msg = 'hello %d'%i 16 #像进程池加入要执行的事件 17 pool.apply_async(worker,(msg,)) 18 #关闭进程池事件加入通道,即不能再向进程池中加入事件 19 pool.close() 20 #阻塞等待进程池出来事件结束后回收进程池 21 pool.join() 22 $ python3 pool1.py 23 hello 1 24 hello 0 25 hello 3 26 hello 2 27 hello 4 28 hello 5 29 hello 7 30 hello 6 31 hello 8 32 hello 9
Pool :
功能:创建进程池;
参数: processes 进程池中进程的数量;
apply_async()
功能: 将异步的方式要执行的事件放入进程池;
参数: func 要执行的函数
args 给函数按位置传参
kwds 给函数按照键值传参
返回值: 返回事件执行后的返回值对象,可以通过调用get()函数获取事件函数return的内容;get() 函数获取事件函数return内容;
apply()
功能:按照顺序添加要执行的事件,执行一个添加一个;
close()
功能:关闭进程池,使其不能再加入新的事件;
join()
功能:阻塞等待进程池将事件都执行结束后回收进程池;
1 #!/usr/bin/python3 2 3 import multiprocessing as mp 4 from time import sleep 5 import os 6 7 def worker(msg): 8 sleep(2) 9 print(msg) 10 return 'worker msg' + msg 11 12 #创建进程池对象,进程池中包含4个进程 13 pool = mp.Pool(processes = 4) 14 15 result = [] 16 for i in range(10): 17 msg = 'hello %d'%i 18 #像进程池加入要执行的事件 19 r = pool.apply_async(worker,(msg,)) 20 #pool.apply(worker,(msg,)) 21 result.append(r) 22 23 print(result) 24 #获取每个事件函数的返回值 25 for res in result: 26 print(res.get()) 27 #关闭进程池事件加入通道,即不能再向进程池中加入事件 28 pool.close() 29 #阻塞等待进程池出来事件结束后回收进程池 30 pool.join()
map()
功能: 类似于内建函数map,将第二个参数的迭代对象中的数据逐个带入第一个函数作为参数。只不过兼顾了apply_async功能,将函数放入进程池
pool.map(fun, test) ====>
for i in test:
pool.apply_async(fun, (i, ))
1 $ cat pool4.py 2 #!/usr/bin/python3 3 4 from multiprocessing import Pool 5 import time 6 7 def fun(fn): 8 time.sleep(1) 9 return fn * fn 10 11 test = [1,2,3,4,5,6] 12 13 print('顺序执行:') 14 s = time.time() 15 #map(fun,test) 16 for i in test: 17 fun(i) 18 e = time.time() 19 print('执行时间:',e - s) 20 21 print('进程池执行') 22 pool = Pool(processes = 4) 23 r = pool.map(fun, test) 24 25 pool.close() 26 27 pool.join() 28 print('执行时间:',time.time() - e) 29 ##### 30 $ python3 pool4.py 31 顺序执行: 32 执行时间: 6.011707782745361 33 进程池执行 34 执行时间: 2.294673204421997
创建自己的进程类;
1, 继承Process类以获取原有的属性
2,实现自己需要的功能部分;
3,使用自己的类创建进程即可;
1 from multiprocessing import Process 2 import time 3 4 class ClockProcess(Process): 5 def __init__(self, *args, **kwargs): 6 Process.__init__(self) 7 self.value = value 8 9 #在proces类中实现,现在重写这个函数 10 def run(self): 11 n = 5 12 while n > 0: 13 print('The time is {}'.\ 14 format(time.ctime())) 15 time.sleep(self.value) 16 n -= 1 17 18 #s使用自己的进程类创建进程对象 19 p = ClockProcess(2) 20 #start后会自动执行run函数 21 p.start() 22 p.join()
进程间的通信:
不同的进程间进行数据的传输;
方法1: 文件进行进程间通信(和磁盘交互慢,不安全)
新的进程间通信方式:
管道 消息队列 共享内存 信号 套接字;
练习1:
1 import os 2 3 #获取文件的大小 4 size = os.path.getsize('file') 5 6 #在创建进程前获取文件对象,子进程接受后父子 7 #进程使用同一个文件偏移量会造成混乱 8 # f = open('file','r') 9 10 pid = os.fork() 11 12 if pid < 0: 13 print("不想动") 14 #子进程拷贝前半部分 15 elif pid == 0: 16 n = size // 2 17 fw = open('child','w') 18 with open('file','r') as f: 19 while True: 20 if n < 64: 21 data = f.read(n) 22 fw.write(data) 23 break 24 data = f.read(64) 25 fw.write(data) 26 n -= 64 27 fw.close() 28 29 #父进程后半部分 30 else: 31 fw = open('parent','w') 32 with open('file') as f: 33 f.seek(size // 2,0) 34 while True: 35 data = f.read(64) 36 if not data: 37 break 38 fw.write(data) 39 fw.close()