#创建进程的方式一
from multiprocessing import Process
import time
def task(name):
print('%s is running'%name)
time.sleep(2)
print('%s is over'%name)
'''
# 注意:在window系统里,创建进程会将代码以模块的方式从头到尾加载一遍
# 创建进程的代码块要写在 if __name__ == '__main__': 里面,避免出错
# 强调:函数名一旦加括号,执行优先级最高,会马上执行。
'''
if __name__ == '__main__':
p = Process(target=task,args=('michael',)) #这句话实例了一个Process对象
p.start() #告诉操作系统创建一个进程
print('我是主进程!')
#实际输出的结果:我是主进程!
#michael is running
#michael is over
#解释:操作系统创建进程的时间比代码运行的速度要慢,所以先将主进程的输出结果打印出来
#创建进程的方式二
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self,name):
super().__init__()
self.name = name
#必须写run方法
def run(self):
print('%s is running'%self.name)
time.sleep(2)
print('%s is over'%self.name)
if __name__ == '__main__':
obj = MyProcess('michael')
obj.start()
print('我是主进程!')
join方法
from multiprocessing import Process
import time
def task(name,n):
print('%s is running'%name)
time.sleep(n)
print('%s is over'%name)
# if __name__ == '__main__':
# p1 = Process(target=task,args=('egon1',1))
# p2 = Process(target=task,args=('egon2',2))
# p3 = Process(target=task,args=('egon3',3))
# start_time = time.time() #系统创建进程的时间
# p1.start() #这行代码只是告诉操作系统需要创建进程
# p2.start()
# p3.start()
# p1.join() #join的作用: 让主进程等待子进程结束,然后再运行主进程,并不会影响子进程的运行
# p2.join()
# p3.join()
# print('我是主进程',time.time()-start_time) #记录主进程等待的时间
# 上面冗余的代码可以简化
if __name__ == '__main__':
start_time = time.time()
p_list = []
for i in range(3):
p = Process(target=task,args=('子进程%s'%i,i))
p.start()
p_list.append(p)
for p in p_list:
p.join()
print('主进程',time.time()-start_time)
#进程间数据隔离
from multiprocessing import Process
x = 100
def task():
global x
x = 0
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join() #加上join 为了确保先运行子进程
print('主进程',x) #主进程 100
#结果说明:每个进程之间的数据是彼此隔离的!
#进程对象其他相关方法
from multiprocessing import Process
import time
import os
def task():
print('子进程自己的pid',os.getpid())
time.sleep(3)
print('子进程父级的pid',os.getppid())
#is_alive的使用 判断子进程是否存活
if __name__ == '__main__':
p = Process(target=task)
p.start()
print(p.is_alive()) #True 此时的子进程是存在的
p.join(4) #join()里的参数需要大于sleep的参数,不然还是会自动运行,当没有参数时,默认等子进程执行完
print(p.is_alive()) #False is_alive() 放在join后会自动将子进程销毁,因此不存在
print('我是主进程')
print(p.pid) #查看子进程自己的pid
# termininate的使用 杀死子进程
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.terminate() #关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
print(p.is_alive()) #True
p.join()
print('我是主进程!')
print(p.is_alive()) #False
#守护进程
主进程创建守护进程:
特点1:守护进程会在主进程代码执行结束后就终止
特点2:守护进程内无法再开启子进程,否则会抛出异常
例子1:
from multiprocessing import Process
import time
def task(name):
print('%s正活着'%name)
time.sleep(2)
print('%s正在死亡'%name)
if __name__ == '__main__':
p = Process(target=task,args=('子进程',))
p.daemon = True #一定要在p.start前设置,设置子线程p为主线程的守护进程,禁止p创建子线程
#并且父进程代码执行结束,p也将终止运行,由于操作系统的处理时间较慢,正常情况下都是直接执行完父进程就结束了
p.start()
# p.daemon = True 将daemon放在 start 后面会报错!
print('主进程正在死亡')
例子2:
from multiprocessing import Process
from threading import Thread
import time
def foo():
print(123)
time.sleep(1)
print("end123")
def bar():
print(456)
time.sleep(1)
print("end456")
if __name__ == '__main__':
p1=Process(target=foo)
p2=Process(target=bar)
p1.daemon=True
p1.start()
p2.start()
# p1.join() #当加上了join后,子进程会正常执行,此时的daemon好像不起作用了!下面有详解!
print("main-------")
#join 与daemon之间的关系
1 Python 默认参数创建线程后,不管主线程是否执行完毕,都会等待子线程执行完毕才一起退出,有无join结果一样
2 如果创建线程,并且设置了daemon为true,即thread.setDaemon(True), 则主线程执行完毕后自动退出,
不会等待子线程的执行结果。而且随着主线程退出,子线程也消亡。
3 join方法的作用是阻塞,等待子线程结束,join方法有一个参数是timeout,即如果主线程等待timeout,
子线程还没有结束,则主线程强制结束子线程。
4 如果线程daemon属性为False, 则join里的timeout参数无效。主线程会一直等待子线程结束。
5 如果线程daemon属性为True, 则join里的timeout参数是有效的, 主线程会等待timeout时间后,结束子线程。
此处有一个坑,即如果同时有N个子线程join(timeout),那么实际上主线程会等待的超时时间最长为 N timeout,
因为每个子线程的超时开始时刻是上一个子线程超时结束的时刻。
#僵尸进程与孤儿进程
'''回收子进程的pid等信息的两种方式:
1、父进程正常结束
2、join方法
'''
互斥锁
#模拟抢票
from multiprocessing import Process,Lock
import json
import time
import random
def search(i):
with open('info','r',encoding='utf-8') as f:
data = json.load(f)
print('剩余票数为%s'%data.get('ticket'))
def buy(i):
#买票前还需要查看是否还有票!
with open('info','r',encoding='utf-8')as f:
data = json.load(f)
#模拟网络延迟
time.sleep(random.randint(1,3))
if data.get('ticket') > 0:
data['ticket'] -= 1 #买票,库存减一
#将更新的信息重新写入文件
with open('info','w',encoding='utf-8')as f:
json.dump(data,f)
print('用户%s抢票成功'%i)
else:
print('没有余票,用户%s抢票失败!'%i)
def run(i,mutex):
search(i) #所有的进程查询的余票数为一致的,大家的起点一致 这一步应该放入到mutex.acquire下
mutex.acquire() #抢锁 一把锁只能被一个人抢到,其他人等待锁被释放
buy(i)
mutex.release() #释放锁,其他人又处于同一地步了
if __name__ == '__main__':
mutex = Lock()
for i in range(10):
p = Process(target=run,args=(i,mutex))
p.start() #产生10个子进程
互斥锁补充:不要随便使用
特点:牺牲了效率但是保证了数据的安全,解决了多个进程操作同一分数据,造成数据不安全的情况。
锁一定要在主进程中创建,给子进程使用:
加锁会将并发变成串行
锁通常用在对数据操作的部分,并不是对进程全程加锁
#小点:
from multiprocessing import Process
import time, os
def task():
print('%s is running' % os.getpid())
# time.sleep(3)
if __name__ == '__main__':
p = Process(target=task)
p.start()
print(p.is_alive()) #True
p.join() # 等待进程p结束后,join函数内部会发送系统调用wait,去告诉操作系统回收掉进程p的id号
print(p.pid) # ???此时能否看到子进程p的id号 可以看到
print(p.is_alive()) #False
print('主')
print(p.pid) #依然存在
'''
上述问题的解释:
p.join()是向操作系统发送请求,告知操作系统 子进程p的id号不需要再占用了,回收就可以,
此时在父进程内还可以看到p.pid,但此时的p.pid是一个无意义的id号,因为操作系统已经将该编号回收
'''