Python之路PythonThread,第三篇,进程3
python3 进程3
管道
在内存中开辟一个管道空间,对多个进程可见。 在通信形式上形成一种约束;
linux 文件类型
b c d - l s p
目录 普通文件 链接 套接字 管道
multiprocessing -----> Pipe函数
Pipe(duplex)
功能:创建一个管道
参数:duplex 默认为True 表示管道为双向管道(全双工);
如果设置为False, 则表示管道为单向管道;
返回值:返回两个管道流对象,分配表示管道的两端;
如果参数为True(默认),两个对象均可发送接收;
如果为False时,则第一个对象只能接收,第二个对象只能发送;
说明:1, 向管道发送数据使用send()函数,从管道接收数据使用recv() 函数;
2,recv() 函数为阻塞函数,当管道中数据为空时会阻塞;
3,一次recv() ,只能接收一次send()的内容;
4,send() 可以发送字符串数字列表等多种类型数据;
1 from multiprocessing import Process,Pipe 2 import os,time 3 4 #创建管道对象 5 #当参数为False的时候child只能recv parent只能send 6 # child_conn,parent_conn = Pipe(False) 7 8 child_conn,parent_conn = Pipe() 9 10 #子进程函数 11 def fun(name): 12 time.sleep(1) 13 #发送一个字符串到管道 14 child_conn.send('hello' + str(name)) 15 print(os.getppid(),"----",os.getpid()) 16 17 jobs = [] 18 #创建5个子进程 19 for i in range(5): 20 p = Process(target = fun,args = (i,)) 21 jobs.append(p) 22 p.start() 23 24 for i in range(5): 25 data = parent_conn.recv() 26 print(data) 27 28 for i in jobs: 29 i.join()
消息队列:
multiprocessing ---> Queue
在内存中开辟一个队列模型,用来存放消息,任何拥有队列队形的进程都可以进行消息的存放和取出;
Queue(maxsize = 0)
功能:创建一个消息队列对象;
参数:maxsize 默认为0 表示消息队列可以存放的消息由系统自动分配的空间而定;
> 0 的正整数 表示队列中最多存放多少条消息;
返回值:消息队列对象;
q.put()
1,向消息队列中存放一条消息,当消息队列满的时候,会阻塞;
2, 存放的消息类型可以是数字,列表,字符串等;
q.full()
判断队列是否为满, 如果满则返回True,否则返回False;
q.qsize()
查看当前队列中消息数量;
q.get()
获取消息,每次获取一条; 当消息队列为空时,则为阻塞;
说明: put() 、get() 中block参数和timeout参数
block默认为True,表示两个函数都是阻塞函数;
如果设置为False, 则表示不阻塞;
timeout 当block设置为True时,表示超时等待时间;
1 from multiprocessing import Queue 2 3 #创建消息队列对象 4 q = Queue(3) 5 6 i = 0 7 # 存放消息 8 while True: 9 #判断队列是否满了 10 if q.full(): 11 print("queue is full") 12 break 13 q.put("hello" + str(i)) 14 i += 1 15 16 print("当前队列有%d条消息"%q.qsize()) 17 18 for i in range(q.qsize()): 19 print("获取消息%s"%q.get()) 20 21 print("is empty?",q.empty()) 22 23 print(q.get(True,3)) 24 25 print("process over")
1 from multiprocessing import Process,Queue 2 import time 3 4 q = Queue() 5 6 def fun(name): 7 time.sleep(1) 8 q.put("hello" + str(name)) 9 10 jobs = [] 11 12 for i in range(10): 13 p = Process(target = fun,args =(i,)) 14 jobs.append(p) 15 p.start() 16 17 for i in jobs: 18 i.join() 19 20 while not q.empty(): 21 print(q.get())
共享内存
在内存中开辟一段内存空间存储数据,每次存储的内容会覆盖上次的内容;由于没有对内存进行格式化修饰,所以存储的速度快效率高;
from multiprocessing import Value,Array
obj = Value(ctype, obj)
功能:开辟共享内存
参数:ctype 要转变的c的类型
obj 要写入共享内存的初始值
obj.value 属性为获取共享内存中的值;
1 from multiprocessing import Value,Process 2 import time 3 import random 4 5 def deposite(money): 6 for i in range(100): 7 time.sleep(0.03) 8 money.value += random.randint(1,200) 9 10 def withdraw(money): 11 for i in range(100): 12 time.sleep(0.02) 13 money.value -= random.randint(1,150) 14 15 money = Value('i',2000) 16 17 d = Process(target = deposite,args = (money,)) 18 w = Process(target = withdraw,args = (money,)) 19 20 d.start() 21 w.start() 22 23 d.join() 24 w.join() 25 26 print(money.value)
obj =Array(ctype, obj)
功能: 开辟一个共享内存空间;
参数: 要装的c的类型;
obj 放入共享内存中的数据, 是一个列表,要求列表重点数据为相同类型的数据;
如果obj传入一个正数,则表示在共享内存中开辟一个多大的空间,空间中可以存放的数值类型由ctype确定;
返回值: 返回一个可迭代对象通过for循环取值,可以进行修改;
from multiprocessing import Process,Array import time import ctypes def fun(shm): for i in shm: print(i) # shm[0] = 'A' # shm = Array('i',[1,2,3,4,5]) shm = Array(ctypes.c_char,6) p = Process(target = fun,args = (shm,)) p.start() p.join() for i in shm: print(i)
############
管道 消息队列 共享内存
开辟空间 : 内存中 内存中 内存中
读写方式: 可双向/单向 先进先出,按照个数存储 操作内存
效率 : 一般 一般 较快
是否需要同步互斥 : 不需要 不需要 需要
#############
信号:
kill -l 查看系统信号
kill -signame PID 给进程号PID的进程发送signame信号;
信号: 信号名称 含义 默认处理方式
名称:系统定义
含义:系统定义
处理方式:采用默认方式处理(系统定义 终止 暂停 忽略)
忽略信号(当信号没发生过)
采用自定义方式处理
1 import signal 2 import time 3 4 signal.alarm(5) 5 #采用默认方式 6 # signal.signal(signal.SIGINT,signal.SIG_DFL) 7 8 #忽略该信号 9 signal.signal(signal.SIGINT,signal.SIG_IGN) 10 signal.signal(signal.SIGALRM,signal.SIG_IGN) 11 12 while True: 13 time.sleep(2) 14 print("你按ctrl + c啊")
1 from signal import * 2 import os,time 3 4 #信号处理函数,有固定参数格式 5 def handler(sig,frame): 6 if sig == SIGALRM: 7 print("收到了时钟信号") 8 elif sig == SIGINT: 9 print("收到了SIGINE就不结束") 10 11 alarm(7) 12 13 #通过函数 处理信号 14 signal(SIGALRM,handler) 15 signal(SIGINT,handler) 16 17 while True: 18 print("waiting for signal") 19 time.sleep(2)
如何发送信号:
os.kill(pid, sig)
功能:向一个进程发送一个信号
参数:pid 指要发送进程的PID号
sig 指要发送的信号
signal.alarm(sec)
功能:给自己发送一个时钟信号(SIGALRM)
参数:esc 秒数 表示在相应的秒数后发送时钟信号
说明:1,信号是一种异步的进程间通信方式
2,alarm函数在一个进程中如果使用多次,则后面的时钟时间会覆盖前面的时间。
信号的处理:
signal.pause() 阻塞等待一个信号的发生;
signal.signal(signum, hander)
功能: 处理信号
参数:signum 表示可以处理的信号
hander 信号处理的方法:
1, 默认处理方式:SIG_DFL
2,忽略信号:SIG_IGN
3,自定义的方式: function
说明:1, signal 函数也是一个异步处理信号函数;
2, SIGSTOP 和SIKILL不能被signal函数处理;
####
僵尸进程的信号处理方案 父进程中
signal(SIGCHLD, SIG_IGN)
###
同步和互斥
临界资源:对多个进程或者线程都可见的资源,容易产生争夺,我们将这类资源叫做临界资源;
临界区:对临界资源进行操作的代码区域称之为临界区;
解决资源争夺方法: 同步 或者 互斥
同步: 同步是一种合作关系,为完成某种任务而建立的多个进程或者线程之间的协调调用,持续等待,传递消息告知资源占用情况;
互斥: 互斥是一种制约关系,当一个进程或者线程进入到临界区后会进行枷锁操作,此时其他进程或者线程无法进入到临界区,只有
当该进程或线程使用后进程解锁,其他人才可以使用,这种技术往往是通过阻塞完成;
Event 事件
Event() ----> 事件对象e
e.wait() : 产生一种阻塞 ,知道e被set之后才结束阻塞
e.set() : 将e set操作 wait不再阻塞
e.is_set() : 判断e是否是被设置的状态
e.clear() : 将e 变成 没有被设置的状态
1 from multiprocessing import Event 2 3 #生成事件对象 4 e = Event() 5 6 #检测事件对象,如果被设置则返回True否则返回false 7 print(e.is_set()) 8 9 #设置事件对象 10 e.set() 11 12 #提供事件的阻塞 13 e.wait() 14 15 print("wait.....") 16 #清除对事件的设置 17 e.clear() 18 19 e.wait() 20 21 print("wait...wait.....")
1 from multiprocessing import Process,Event 2 import time 3 4 def wait_event(): 5 print('process1要等主进程操作完我才能操作') 6 e.wait() 7 print('终于操作完了,该我了',e.is_set()) 8 9 def wait_event_timeout(): 10 print('process2要等主进程操作完我才能操作') 11 e.wait(2) 12 print('我等不了了,干别的去',e.is_set()) 13 14 e = Event() 15 16 p1 = Process(name = 'block',\ 17 target = wait_event) 18 p1.start() 19 p2 = Process(name = 'non-block',\ 20 target = wait_event_timeout) 21 p2.start() 22 23 print("假设主进程在忙碌的操作临界区") 24 time.sleep(3) 25 e.set() 26 print("主进程开放临界区")
练习:
1. 创建父子进程,分别表示司机和售票员
2. 当售票员捕捉到 SIGINT信号时 给司机发送SIGUSR1信号,
司机打印“老司机开车了”
当售票员捕捉到 SIGQUIT信号时 给司机发送SIGUSR2信号,
司机打印“系好安全带,小心甩出去”
当司机捕捉到 SIGTSTP信号时 给售票员发送SIGUSR1信号,
售票员打印“到站了,下车吧”
3. 到站后 售票员先下车(子进程先退出),然后司机下车
1 from signal import * 2 from multiprocessing import Process 3 import os 4 import time 5 6 def saler_handler(sig,frame): 7 if sig == SIGINT: 8 os.kill(os.getppid(),SIGUSR1) 9 elif sig == SIGQUIT: 10 os.kill(os.getppid(),SIGUSR2) 11 elif sig == SIGUSR1: 12 print("python学完了,出去试试吧") 13 os._exit(0) 14 15 def driver_handler(sig,frame): 16 if sig == SIGUSR1: 17 print("老司机带你学python") 18 elif sig == SIGUSR2: 19 print("python 知识多,积累最重要") 20 elif sig == SIGTSTP: 21 os.kill(p.pid,SIGUSR1) 22 23 def saler(): 24 signal(SIGINT,saler_handler) 25 signal(SIGQUIT,saler_handler) 26 signal(SIGUSR1,saler_handler) 27 signal(SIGTSTP,SIG_IGN) 28 while True: 29 time.sleep(2) 30 print("开着python去远方") 31 32 p = Process(name = 'zhangjie',\ 33 target = saler) 34 p.start() 35 36 # 父进程处理信号部分 37 signal(SIGUSR1,driver_handler) 38 signal(SIGUSR2,driver_handler) 39 signal(SIGTSTP,driver_handler) 40 signal(SIGINT,SIG_IGN) 41 signal(SIGQUIT,SIG_IGN) 42 43 p.join()