process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。
创建模块 import os import time from multiprocessing import Process def func(n,name,num = 20): print(os.getpid(),os.getppid()) time.sleep(1) if __name__ == '__main__': print(os.getpid(),os.getppid()) # process id,parent process id Process(target=func,args=[1,'alex',30]).start() # func print('*'*20) time.sleep(0.5) print('*'*40) # p = Process(target=func) # p.start() # 主进程默认会等待子进程执行完毕之后才结束 # 主进程和子进程之间的代码是异步的 # 为什么主进程要等待子进程结束 回收一些子进程的资源 # 开启一个进程是有时间开销的 :操作系统响应开启进程指令,给这个进程分配必要的资源
强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号 参数介绍: 1 group参数未使用,值始终为None 2 target表示调用对象,即子进程要执行的任务 3 args表示调用对象的位置参数元组,args=(1,2,'egon',) 4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} 5 name为子进程的名称
方法介绍:
1 p.start():启动进程,并调用该子进程中的p.run()
2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
3 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别
小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
4 p.is_alive():如果p仍然运行,返回True
5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时
间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程。
属性介绍:
1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定
为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 p.name:进程的名称
3 p.pid:进程的pid
4 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层
进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,
而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子
进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候 ,就不会递归运行了。
同步控制
import os
from multiprocessing import Process
def func(exp):
print(os.getpid(),os.getppid())
result = eval(exp)
with open('file','w') as f:
f.write(str(result))
if __name__ == '__main__':
print(os.getpid(),os.getppid()) # process id,parent process id
# 3*5+5/6
p = Process(target=func,args=['3*5']) # func
p.start()
ret = 5/6
p.join() # join方法能够检测到p进程是否已经执行完了,阻塞直到p执行结束
with open('file') as f:
result = f.read()
ret = ret + int(result)
print(ret)
join :阻塞 直到 子进程结
开启多个进程
import os
import time
from multiprocessing import Process
def process(n):
print(os.getpid(),os.getppid())
time.sleep(1)
print(n)
if __name__ == '__main__':
p_lst = []
for i in range(10):
p = Process(target=process,args=[i,])
p.start()
p_lst.append(p)
for p in p_lst:p.join() # 检测p是否结束 如果没有结束就阻塞直到结束 如果已经结束了就不阻塞
print('求和')
还有一种以继承Process类的形式开启进程的方式
import os
from multiprocessing import Process
class Myprocess(Process):
def __init__(self,*args):
super().__init__()
self.args = args
def run(self):
print(os.getpid(),self.name,self.pid)
for name in self.args:
print('%s和女主播聊天'%name)
if __name__ == '__main__':
print(os.getpid())
p = Myprocess('yuan','wusir')
p.start() # 在执行start的时候,会帮我们主动执行run方法中的内容
进程中的数据隔离
from multiprocessing import Process
n = 100
def func():
global n
n += 1
print('son : ',n) #son : 101
if __name__ == '__main__':
p = Process(target=func)
p.start()
p.join()
print(n) #100
守护进程
import time
from multiprocessing import Process
def func():
print('son start')
while True:
time.sleep(1)
print('son')
def func2():
print('start :in func2')
time.sleep(5)
print('end : in func2')
if __name__ == '__main__':
p = Process(target=func)
# 在一个进程开启之前可以设置它为一个守护进程
p.daemon = True
p.start()
Process(target=func2).start()
time.sleep(2)
print('在主进程中')
分析:
主进程的代码 大概在2s多的时候就结束了
p2子进程实在5s多的时候结束
主进程结束
p是在什么时候结束的?
p是在主进程的代码执行完毕之后就结束了
主进程会等待子进程的结束而结束
守护进程的意义:
子进程会随着主进程代码的执行结束而结束
注意:守护进程不会关心主进程什么时候结束,我只关心主进程中的代码什么时候结束
守护进程的作用:
守护主进程,程序报活
主进程开启的时候 建立一个守护进程
守护进程只负责每隔1分钟 就给检测程序发一条消息
进程中的其他属性和方法
import time
from multiprocessing import Process
def func():
print('wahaha')
time.sleep(20)
print('wahaha end')
if __name__ == '__main__':
p = Process(target=func)
p.start()
print(p.is_alive())
time.sleep(1)
p.terminate() # 在主进程中结束一个子进程
print(p.is_alive())
time.sleep(0.5)
print(p.is_alive())
print(p.pid) #相当于self.pid 查看进程ID
print(p.name) #相当于self.name 查看进程名
使用多进程实现socket聊天并发-server
server端
import socket
from multiprocessing import Process
def func(conn):
while True:
msg = conn.recv(1024).decode('utf-8')
print(msg)
conn.send('sb'.encode('utf-8'))
conn.close()
if __name__ == "__main__":
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
while True:
conn, addr = sk.accept()
Process(target=func,args=[conn,]).start()
sk.close()
client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
inp = input('>>>').encode('utf-8')
sk.send(inp)
msg = sk.recv(1024).decode('utf-8')
print(msg)
sk.close()
锁
import os import time import random from multiprocessing import Process from multiprocessing import Lock def work(n,lock): lock.acquire() print('%s: %s in running'%(n,os.getpid())) time.sleep(random.random()) print('%s:%s in done'%(n,os.getpid())) lock.release() if __name__ =='__main__': lock = Lock() for i in range(10): p = Process(target=work, args=(i,lock)) p.start()
抢票系统
import json
import time
import random
from multiprocessing import Process,Lock
def chenck(i):
with open('file')as f:
count = json.load(f)
print('percon%s,剩余%s张票'%(i,count['count']))
time.sleep(random.random())
def buy(i,lock):
chenck(i)
lock.acquire()
with open('file')as f:
count = json.load(f)
time.sleep(random.random())#模拟读数据的网络延迟
if count['count'] > 0:
print('%s抢票成功'%i)
else:
print('%s抢票失败'%i)
time.sleep(random.random())#模拟读数据的网络延迟
with open('file','w')as f:
count['count'] -= 1
json.dump(count,f)
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(10): #模拟并发10个客户端抢票
Process(target=buy, args=[i, lock]).start()
上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速
度却保证了数据安全。
虽然可以用文件共享数据实现进程间通信,但问题是:
1.效率低(共享数据基于文件,而文件是硬盘上的数据)
2.需要自己加锁处理
信号量
KTV 4个房子
import time
import random
from multiprocessing import Process,Semaphore
def ktv(i,sem):
sem.acquire()
print('person %s 进来唱歌了'%i)
time.sleep(random.randint(1,5))
print('person %s 从ktv出去了'%i)
sem.release()
if __name__ == '__main__':
sem = Semaphore(4)
for i in range(10):
Process(target=ktv,args=(i,sem)).start()
锁+计数器
.acquire() 计数器-1
计数器减为0 = 阻塞
.release() 计数器+1
事件--------------红绿灯
multiprocess.Event(了解)
状态
# 子进程 如何 受到状态的影响?
# wait() 的方法 等待 ---> 信号
# 发送信号:通过事件来发送信号
# True set 把信号设置为True
# False clear 把信号设置位False
# 红绿灯 :
# 车 进程 wait() 等红灯
# 根据状态变化 wait遇到True信号,就非阻塞
# 遇到False信号,就阻塞
# 交通灯 进程 红灯 --> False
# 绿灯 --> True
# 事件
# wait的方法 根据一个状态来决定自己是否要阻塞
# 状态相关的方法
# set 将状态改为T
# clear 将状态改为F
# is_set 判断当前的状态是否为T
# from multiprocessing import Event
# # 创建一个事件的对象
# e = Event()
# print(e.is_set()) # 在事件的创世之初,状态为False
# e.set()
# e.wait()
# print(e.is_set())
# e.clear()
# print(e.is_set())
# e.wait()
import time
import random
from multiprocessing import Process,Event
def car(i,e): # 感知状态的变化
if not e.is_set(): # 当前这个事件的状态如果是False
print('car%s正在等待'%i) # 这辆车正在等待通过路口
e.wait() # 阻塞 直到有一个e.set行为 # 等红灯
print('car%s通过路口'%i)
def traffic_light(e): # 修改事件的状态
print('