Python入门学习
DAY34
今日内容:
1. 开启子进程的两种方式
2. 进程之间的内存隔离
3. 进程对象相关属性
4. 守护进程
5. 互斥锁
6. 僵尸进程与孤儿进程
进程原理参考:http://www.cnblogs.com/linhaifeng/articles/7430066.html#_label4
开启子进程的两种方式
方式一:
from multiprocessing import Process import time def task(name): print('%s is running' % name) time.sleep(3) # 模拟子进程生命周期 print('%s is done' % name) #在windows系统上,开启子进程的操作必须放到if __name__ == '__main__':的子代码中 if __name__ == '__main__': p = Process(target=task,args=('subprocess1',)) # 注意,args必须传入元祖 p.start() # 想操作系统发送一个开启子进程的信号 print('主进程 is running...')
方式二:
from multiprocessing import Process import time class Myprocess(Process): # 自定义一个process类,基础Process def __init__(self,name): super().__init__() self.name=name def run(self): print('%s is running' % self.name) time.sleep(3) print('%s is done' % self.name) if __name__ == '__main__': p = Myprocess('subprocess1') p.start() # 当启动子进程时,自动运行run() print('主程序 is running...')
进程之间的内存隔离
from multiprocessing import Process n = 100 def task(): global n n = 0 print(n) # 0 if __name__ == '__main__': p = Process(target = task) p.start() print(n) # 100
进程对象相关属性
1. join方法的使用
join:让主进程在原地等待,等待子进程运行完毕,不会影响子进程的执行
from multiprocessing import Process import time def task(name,n): print('%s is running'%name) time.sleep(n) print('%s is done'%name) if __name__ == '__main__': start = time.time() p_l=[] for i in range(1,4): # 创建多个子进程 p = Process(target=task,args=('子%s'%i,i)) p_l.append(p) p.start() for p in p_l: p.join() print('主进程',(time.time()-start))
2. 进程pid: 每一个进程在操作系统内都有一个唯一的id号,称之为pid
有两种方式可以获得进程pid
方式一:current_process 方法
from multiprocessing import Process,current_process def task(): print('子进程 is running... %s'%current_process().pid) if __name__ == '__main__': p = Process(target=task) p.start()
方式二:os 模块的getpid方法可以获得进程pid, getppid方法可以获得父进程的pid
from multiprocessing import Process import os def task(): print('子进程 is running... %s'%os.getpid()) print('子进程 is running... %s'%os.getppid()) if __name__ == '__main__': p = Process(target=task) p.start() print('主进程..',os.getpid()) print('主进程..',os.getppid())
3. name方法:子进程会有默认进程名,第一个子进程默认Process-1 第二个子进程默认Process-2
from multiprocessing import Process, current_process def task(): print('子进程 is running...') if __name__ == '__main__': p = Process(target=task, name='子进程') p.start() print(p.name) # 子进程 print('主进程..')
4. terminate() 和 is_alive()
terminate(): 终结进程
is_alive(): 判断进程是否存活
from multiprocessing import Process, current_process import time def task(): print('子进程 is running...' ) if __name__ == '__main__': p = Process(target=task, name='子进程') p.start() p.terminate() # 终结子进程 time.sleep(0.1) # 因为终结之后就判断了是否存活,操作系统还没来及的回收子进程,所以不睡眠就会显示存活 print(p.is_alive()) # 判断子进程是否存活 False print('主进程..')
守护进程
一:守护进程会在主进程代码执行结束后就终止
二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止
from multiprocessing import Process import time def task(name): print('%s is running..' % name) time.sleep(3) print('%s is done..' % name) if __name__ == '__main__': p = Process(target=task,args=('守护进程',)) p.daemon = True p.start() time.sleep(1) print('主程序 is done')
互斥锁
Lock 方法
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,
而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理
模拟抢车票:
from multiprocessing import Process, Lock import json import time import random def search(name): with open('db.json', 'rt', encoding='utf-8') as f: dic = json.load(f) time.sleep(1) print('%s 查看余票为 %s' % (name, dic['count'])) def get(name): with open('db.json', 'rt', encoding='utf-8') as f: dic = json.load(f) if dic['count'] > 0: dic['count'] -= 1 time.sleep(random.randint(1, 3)) with open('db.json', 'wt', encoding='utf-8') as f: json.dump(dic, f) print('%s 购票成功' % name) else: print('%s 车票已售尽' % name) def task(name,mutex): search(name) mutex.acquire() get(name) mutex.release() if __name__ == '__main__': mutex = Lock() for i in range(10): p = Process(target=task, args=('客户%s' % i,mutex)) p.start()
僵尸进程与孤儿进程
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。详解如下
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。
以上为本次学习的内容