37_并发编程-进程创建的第二种方法
一、创建进程的第二种方法
1 # 创建进程的第二种方式
2 import os
3 import time
4 from multiprocessing import Process
5
6 class My_process(Process): # 继承Process方法,重写run方法,传参数的时候要写init,但是注意要在init方法中运行父类的init
7
8 def __init__(self, n, name):
9 super().__init__()
10 self.n = n
11 self.name = name
12 print(n)
13
14 def run(self): # 重写Process父类的run方法
15 print('子进程pid>>>', os.getpid())
16 print('子进程')
17
18 if __name__ == '__main__':
19 p1 = My_process(10, name='MYPROCESS') # 创建进程对象
20 p1.start() # 启动进程,向操作系统发送创建进程的指令,调用run方法
21 print(p1.pid) # 获取的是对象p1的进程id
22 print(p1.name) # name父类进程已经构造,在此重写赋值
23 # time.sleep(0.5)
24 print('主进程结束!')
二、Process 其他操作
1、join( )
让主进程加上join的地方等待(也就是阻塞住),等待子进程执行完之后,再继续往下执行我的主进程,好多时候,我们主进程需要子进程的执行结果,所以必须要等待。join感觉就像是将子进程和主进程拼接起来一样,将异步改为同步执行。
空间隔离
1 # 验证并发的空间隔离
2 import time
3 from multiprocessing import Process
4
5 global_num = 10 # 设置一个全局变量
6
7 def func(n):
8 global global_num # 修改全局变量,看子进程修改后,有没有影响主进程的调用
9 global_num = n
10 print('主进程全局变量>>', global_num)
11
12 if __name__ == '__main__':
13 p1 = Process(target=func, kwargs={'n': 0}) # 使用args传递的是元组,使用kwagrs传递的是字典
14 p1.start() # 这里相对于子进程还是异步的
15 p1.join() # 为验证效果,先让子进程运行,join阻塞一下,只有在join的地方才会阻塞住,将子进程和主进程之间的异步改为同步
16 print('主进程全局变量>>', global_num)
2、测试多任务并发时间
多任务并发时间
开多进程-for循环
其他方法
守护进程-1
1 import time
2 from multiprocessing import Process
3
4 def func1(n):
5 time.sleep(n) # 先睡一秒在执行,观察并发,
6 print(n)
7
8 def func2(n):
9 time.sleep(n)
10 print(n)
11
12 def func3(n):
13 time.sleep(n)
14 print(n)
15 if __name__ == '__main__':
16 p1 = Process(target=func1, args=(1,))
17 p2 = Process(target=func2, args=(2,))
18 p3 = Process(target=func3, args=(3,))
19 p1.start()
20 p2.start()
21 p3.start()
22
23 print('主进程结束')
3、开启多进程 - 使用for循环
1 #下面的注释按照编号去看,别忘啦!
2 import time
3 import os
4 from multiprocessing import Process
5
6 def func(x,y):
7 print(x)
8 # time.sleep(1) #进程切换:如果没有这个时间间隔,那么你会发现func执行结果是打印一个x然后一个y,再打印一个x一个y,不会出现打印多个x然后打印y的情况,因为两个打印距离太近了而且执行的也非常快,但是如果你这段程序运行慢的话,你就会发现进程之间的切换了。
9 print(y)
10
11 if __name__ == '__main__':
12
13 p_list= []
14 for i in range(10):
15 p = Process(target=func,args=('姑娘%s'%i,'来玩啊!'))
16 p_list.append(p)
17 p.start()
18
19 [ap.join() for ap in p_list] #4、这是解决办法,前提是我们的子进程全部都已经去执行了,那么我在一次给所有正在执行的子进程加上join,那么主进程就需要等着所有子进程执行结束才会继续执行自己的程序了,并且保障了所有子进程是异步执行的。
20
21 # p.join() #1、如果加到for循环里面,那么所有子进程包括父进程就全部变为同步了,因为for循环也是主进程的,循环第一次的时候,一个进程去执行了,然后这个进程就join住了,那么for循环就不会继续执行了,等着第一个子进程执行结束才会继续执行for循环去创建第二个子进程。
22 #2、如果我不想这样的,也就是我想所有的子进程是异步的,然后所有的子进程执行完了再执行主进程
23 #p.join() #3、如果这样写的话,多次运行之后,你会发现会出现主进程的程序比一些子进程先执行完,因为我们p.join()是对最后一个子进程进行了join,也就是说如果这最后一个子进程先于其他子进程执行完,那么主进程就会去执行,而此时如果还有一些子进程没有执行完,而主进程执行
24 #完了,那么就会先打印主进程的内容了,这个cpu调度进程的机制有关系,因为我们的电脑可能只有4个cpu,我的子进程加上住进程有11个,虽然我for循环是按顺序起进程的,但是操作系统一定会按照顺序给你执行你的进程吗,答案是不会的,操作系统会按照自己的算法来分配进
25 #程给cpu去执行,这里也解释了我们打印出来的子进程中的内容也是没有固定顺序的原因,因为打印结果也需要调用cpu,可以理解成进程在争抢cpu,如果同学你想问这是什么算法,这就要去研究操作系统啦。那我们的想所有子进程异步执行,然后再执行主进程的这个需求怎么解决啊
26 print('不要钱~~~~~~~~~~~~~~~~!')
三、僵尸进程、孤儿进程
参考博客:http://www.cnblogs.com/Anker/p/3271773.html
四、守护进程 - 守护的是父进程
之前我们讲的子进程是不会随着主进程的结束而结束,子进程全部执行完之后,程序才结束,那么如果有一天我们的需求是我的主进程结束了,由我主进程创建的那些子进程必须跟着结束,怎么办?守护进程就来了!
主进程创建守护进程
其一:守护进程会在主进程代码执行结束后就终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止
1 from multiprocessing import Process
2
3 def func(n):
4 print('子进程>>', n)
5
6 if __name__ == '__main__':
7
8 p = Process(target=func, args=(1,))
9 p.start() # 给操作系统发了一个执行子进程的信号,由操作系统执行
10 p.terminate() # 给操作系统发了一个关闭子进程的信号,是否被关闭由操作系统执行
11 time.sleep(1) # 让子进程先执行完成,因为查看是否存活,不能确定操作系统是否及时关闭掉了子进程
12 print(p.is_alive()) # 查看子进程是否还存活
13 print('主进程结束')
1 import os
2 import time
3 from multiprocessing import Process
4
5 class Myprocess(Process):
6 def __init__(self,person):
7 super().__init__()
8 self.person = person
9 def run(self):
10 print(os.getpid(),self.name)
11 print('%s正在和女主播聊天' %self.person)
12 time.sleep(3)
13 if __name__ == '__main__':
14 p=Myprocess('太白')
15 p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
16 p.start()
17 # time.sleep(1) # 在sleep时linux下查看进程id对应的进程ps -ef|grep id
18 print('主')