python进程
multiprocess模块
'process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建'
Process([group [, target [, name [, args [, kwargs]]]]])
#参数介绍:
1 group参数未使用,值始终为None
2 target表示调用对象,即子进程要执行的任务
3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
5 name为子进程的名称
#强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
multiprocess模块方法
#p.start()
启动进程,并调用该子进程中的p.run()
#p.run()
进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
#p.terminate()
强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
#p.is_alive():
如果p仍然运行,返回True
#p.join([timeout])
主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
join方法
# 代码示例:
import time
from multiprocessing import Process
def func():
print("子进程开始执行!")
time.sleep(1)
print("子进程执行完毕!")
if __name__ == '__main__':
print("主进程开始执行!")
p = Process(target=func, )
p.start()
p.join()
print("主进程执行完毕!")
# 执行结果:
主进程开始执行!
子进程开始执行!
子进程执行完毕!
主进程执行完毕!
'当主进程执行到p.join()时,整个程序会阻塞在这里,直到子进程p执行完毕,主进程才能继续向下执行,也就不会出现主进程先于子进程执行完毕的现象了'
代码创建进程
第一种创建进程的方式
# 代码示例
from multiprocessing import Process
def dask(name):
print("%s的子进程"%name)
if __name__ == '__main__':
p = Process(target=dask, args=('kevin',)) # 创建一个进程对象
p.start() # 告诉操作系统创建一个新的进程
print('主进程')
"""
强调:不同的操作系统创建进程的要求不一样
在windows中创建进程是以导入模块的方式进行 所以创建进程的代码必须写在__main__子代码中
否则会直接报错 因为在无限制创建进程
在linux和mac中创建进程是直接拷贝一份源代码然后执行 不需要写在__main__子代码中
"""
第二种继承的形式创建进程
'自定义一个类,继承Process类,必须写一个run()方法.如果想要传参,可以自己写一个init方法,然后首先执行super父类的init方法,再写自己的属性'
# 代码示例
from multiprocessing import Process
class MyProcess(Process): # 自定义的类要继承Process类
def __init__(self, n, name):
super().__init__()
# 如果自己想要传参name, 那么要首先用super()执行父类的init方法
self.n = n
self.name = name
def run(self):
print("子进程的名字是>>>", self.name)
print("n的值是>>>", self.n)
if __name__ == '__main__':
p1 = MyProcess(123, name="子进程01")
p1.start()
# 给操作系统发送创建进程的指令,子进程创建好之后,要被执行,执行的时候就会执行run方法
print("p1.name是>>>", p1.name)
print("主进程结束")
# 执行结果:
# p1.name是>>> 子进程01
# 主进程结束
# 子进程的名字是>>> 子进程01
# n的值是>>> 123

进程实现并发
"""
将与客户端通信的代码封装成一个函数
之后每来一个客户端就创建一个进程专门做交互
"""
# 代码示例:
'将服务端的代码封装成函数'
def get_server():
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
return server
'''封装一个get_server,这个创建进程就不会反复执行里面的代码
从而避免报地址只允许使用一次的错误'''
def talk():
while True:
data = socket.recv(1024)
print(data.decode('utf8'))
sock.send(data)
if __name__ == '__main__':
server = get_server()
while True:
sock, addr = server.accept()
p = Process(target=talk,args=(sock,))
p.start()
进程间数据默认隔离
'进程之间是空间隔离的,不共享资源'
#代码示例:
import time
from multiprocessing import Process
global_num = 100
def func(): # 子进程
global global_num
global_num = 0
print("子进程的全局变量>>>", global_num)
if __name__ == '__main__':
p1 = Process(target=func,)
p1.start()
time.sleep(1) # 等待子进程执行结束
print("主进程的全局变量>>>", global_num)
# 执行结果:
子进程的全局变量>>> 0
主进程的全局变量>>> 100
进程对象属性
#代码示例:
from multiprocessing import Process Lock
def dask(name):
print("%s的子进程"%name)
if __name__ == '__main__':
p = Process(target=dask, args=('jason',))
p.start()
p.join()
print("子进程的ID是>>>", p.pid)
print("子进程的名字是>>>", p.name)
print("主进程执行完毕!")
"""
进程号如何查看
windows: tasklist结果集中PID
mac: ps -ef
"""
#查看进程号的方法
1.current_process函数
from multiprocessing import Process, current_process
current_process().pid
# 获取进程号的用处之一就是可以通过代码的方式管理进程
windows taskkill关键字
mac/linux kill关键字
2.os模块
os.getpid() # 获取当前进程的进程号
os.getppid() # 获取当前进程的父进程号
僵尸进程与孤儿进程
# 僵尸进程
'为什么主进程默认需要等待子进程结束才会结束'
所有的子进程在运行结束之后都会变成僵尸进程(死了没死透)
还保留着pid和一些运行过程的中的记录便于主进程查看(短时间保存)
这些信息会被主进程回收(僵尸彻底死了)
1.主进程正常结束
2.调用join方法
# 孤儿进程
# 子进程存活着 父进程意外死亡
子进程会被操作系统自动接管(儿童福利院)
守护进程
'主进程执行结束,由该主进程创建的子进程必须跟着结束'
# 代码示例
from multiprocessing import Process
import time
def dask(name):
print("%s开始执行子进程" % name)
time.sleep(2)
print("%s结束执行子进程" % name)
if __name__ == '__main__':
p = Process(target=dask, args=('jason',))
p.daemon = True
'一定要在p.start()前设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行'
p.start()
print("主进程执行完毕!")
互斥锁
# 代码示例
import json
from multiprocessing import Process
import time
import random
# 查票
def search(name):
with open(r'ticket_data.json', 'r', encoding='utf8') as f:
data = json.load(f)
print(f'{name}查询当前余票:%s' % data.get('ticket_num'))
# 买票
def buy(name):
'''
点击买票是需要再次查票的 因为期间其他人可能已经把票买走了
'''
# 1.查票
with open(r'ticket_data.json', 'r', encoding='utf8') as f:
data = json.load(f)
time.sleep(random.randint(1, 3))
# 2.判断是否还有余票
if data.get('ticket_num') > 0:
data['ticket_num'] -= 1
with open(r'ticket_data.json', 'w', encoding='utf8') as f:
json.dump(data, f)
print(f'{name}抢票成功')
else:
print(f'{name}抢票失败 没有余票了')
def run(name, mutex):
search(name)
mutex.acquire() # 抢锁
buy(name)
mutex.release() # 放锁
# 模拟多人同时抢票
if __name__ == '__main__':
mutex = Lock()
'互斥锁需要产生在主进程 然后再交给多个子进程'
for i in range(1, 10):
p = Process(target=run, args=('用户:%s' % i,mutex))
p.start()
'''当多个进程操作同一份数据的时候会造成数据的错乱!!!
这个时候需要加锁处理(互斥锁)
将并发变成串行 牺牲了效率但是保证的数据的安全
互斥锁并不能轻易使用 容易造成死锁现象
互斥锁只在处理数据的部分加锁 不能什么地方都加 严重影响程序的效率'''
