python进程间通信主要应用于,多进程时,进程间数据的交换和传递。
进程间通信主要有5中方式:
1、管道
2、消息队列
3、共享内存
4、信号
5、套接字
linux文件类型
-
普通文件类型 :-
Linux中最多的一种文件类型, 包括 纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件.第一个属性为 [-] -
目录文件 :d
就是目录, 能用 # cd 命令进入的。第一个属性为 [d],例如 [drwxrwxrwx] -
块设备文件 :b
块设备文件 : 就是存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件。第一个属性为 [b] -
字符设备 :c
字符设备文件:即串行端口的接口设备,例如键盘、鼠标等等。第一个属性为 [c] -
套接字文件 ?
这类文件通常用在网络数据连接。可以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信。第一个属性为 [s],最常在 /var/run目录中看到这种文件类型 -
管道文件 :p
FIFO也是一种特殊的文件类型,它主要的目的是,解决多个程序同时存取一个文件所造成的错误。FIFO是first-in-first-out(先进先出)的缩写。第一个属性为 [p]
1、管道
multiprocessing 中的 Pipe 函数
p,q=Pipe(duplex)
功能 : 创建一个管道
参数 :
duplex 默认为 True 表示管道为双向管道
如果设置为False 则表示管道为单向管道
返回值 :
返回两个管道流对象,分别表示管道的两端
如果参数为True(默认) 两个对象均可发送接受
如果为False时 则第一个对象只能接受,第二个对象只能发送from multiprocessing import Process,Pipe import os,time #创建管道对象 #当参数为False的时候child只能recv parent只能send child_conn,parent_conn = Pipe(False) child_conn,parent_conn = Pipe() #子进程函数 def fun(name): time.sleep(1) #发送一个字符串到管道 child_conn.send('hello' + str(name)) print(os.getppid(),"----",os.getpid()) jobs = [] #创建5个子进程 for i in range(5): p = Process(target = fun,args = (i,)) jobs.append(p) p.start() for i in range(5): data = parent_conn.recv() print(data) for i in jobs: i.join()
2、消息队列
multiprocessing — 》 Queue
在内存中开辟一个队列模型,用来存放消息。任何拥有队列对象的进程都可以进行消息的存放和取出
q=Queue(maxsize = 0)
功能 : 创建一个消息队列对象
参数 : maxsize 默认为0 表示消息队列可以存放的消息有 系统自动分配的空间而定
> 0 正整数 表示队列中最多存放多少条消息
返回值 : 消息队列对象
q.put()
向消息队列中存放一条消息,当消息队列满的时候,会阻塞
存放的消息类型可以使数字列表,字串等
q.full()
判断队列是否为满,如果满则返回True 否则返回False
q.qsize()
查看当前队列中消息数量
q.get()
获取消息,每次获取一条,当消息队列为空是,则阻塞
q.empty()
消息队列为空则返回True 不为空返回False
put get 中block参数和timeout参数
block 默认为True 表示两个函数都是阻塞函数
如果设置为False则表示不阻塞
timeout 当block设置为True的时候表示超时等待时间
from multiprocessing import Process,Queue
import time
q = Queue()
def fun(name):
time.sleep(1)
q.put("hello" + str(name))
jobs = []
for i in range(10):
p = Process(target = fun,args =(i,))
jobs.append(p)
p.start()
for i in jobs:
i.join()
while not q.empty():
print(q.get())
3、共享内存
在内存中开辟一段内存空间存储数据,每次存储的内容会覆盖上次的内容。由于没有对内存进行格式化的修饰所以存取速度块效率高
from multiprocessing import Value,Array
obj = Value(ctype,obj)
功能 : 开辟共享内存
参数 : ctype 要转变的c的类型
obj 要写入共享内存的初始值
obj.value 属性为获取共享内存中的值
obj = Array(ctype,obj)
功能 : 开辟一个共享内存空间
参数 : 要转换的c的类型
obj : 放入共享内存中的数据,是一个列表,要求列表中的数据为相同类型数据
如果obj传入一个正数,则表示在共享内存中开辟一个 多大的空间,空间中可以存放的数值类型 由ctype确定
返回值:返回一个可迭代对象通过for循环取值,可以进行修改
rom multiprocessing import Value,Process
import time
import random
def deposite(money):
for i in range(100):
time.sleep(0.03)
money.value += random.randint(1,200)
def withdraw(money):
for i in range(100):
time.sleep(0.02)
money.value -= random.randint(1,150)
money = Value('i',2000)
d = Process(target = deposite,args = (money,))
w = Process(target = withdraw,args = (money,))
d.start()
w.start()
d.join()
w.join()
print(money.value)
4、信号
kill -l 查看系统信号
kill -signame PID 给进程号PID的进程发送signame信号
信号 : 信号名称 含义 默认处理方法
名称 : 系统定义
含义 : 系统定义
处理方式 : 采用默认方式处理 (系统定义 终止 暂停 忽略
忽略信号(当信号没发生过)
采用自定义的方式处理
如何发送信号:
os.kill(pid,sig)
功能 : 向一个进程发送一个信号
参数 : pid :要发送进程的PID号
sig :要发送的信号
signal.alarm(sec)
功能:给自己发送一个时钟信号 (SIGALRM)
参数: sec : 秒数 表示在相应的秒数后发送时钟信号
- 信号是一种异步的进程间通信方式
- alarm 函数在一个进程中如果使用多次,则后面的时钟时间会覆盖前面的时间
信号的处理:
signal.pause()
阻塞等待一个信号的发生
signal.signal(signum,handler)
功能 : 处理信号
参数 : signum : 表示可以处理的信号
handler : 信号的处理方法
默认处理方式 : SIG_DFL
忽略信号 : SIG_IGN
自定义的方式 : function
-
signal函数也是一个异步处理信号函数
-
SIGSTOP 和 SIGKILL不能被signal函数处理
僵尸进程的信号处理方案 父进程中signal(SIGCHLD,SIG_IGN) from signal import * import os,time #信号处理函数,有固定参数格式 def handler(sig,frame): if sig == SIGALRM: print("收到了时钟信号") elif sig == SIGINT: print("收到了SIGINE就不结束") alarm(7) #通过函数 处理信号 signal(SIGALRM,handler) signal(SIGINT,handler) while True: print("waiting for signal") time.sleep(2)
5、套接字
使用本地套接字实现进程间通信
发送
from socket import *
from time import sleep
address = './sockfile'
s = socket(AF_UNIX,SOCK_STREAM)
try:
s.connect(address)
except error as e:
print(e)
try:
message = b"This is a unix message"
s.send(message)
# sleep(20)
data = s.recv(1024).decode()
print('recv:',data)
except error as e:
print(e)
finally:
s.close()
接收
from socket import *
import os
#设置通信的套接字文件
address = './sockfile'
try:
os.unlink(address) #删除这个目录下的这个文件
except OSError:
if os.path.exists(address): #判断文件是否删除成功
raise
s = socket(AF_UNIX,SOCK_STREAM)
s.bind(address) #绑定本地套接字的文件
s.listen(5)
while True:
conn,addr = s.accept()
print("connect from",addr) #addr是空子串
while True:
data = conn.recv(1024).decode()
if not data:
break
print("receive:",data)
conn.send(b"receive your message")
conn.close()
s.close()