2018.8.14
目录
day07
信号
一个进程向另一个进程通过信号的方式传递某种讯息,接受方在接受到信号作出相应的处理。
示例:
import os
from time import sleep,ctime
while True:
sleep(2)
print(ctime(),os.getpid())
print(ctime(),os.getpid())
#另一终端输入kill -9 pid号,即可结束程序执行
- kill -l 查看信号
- kill -sig pid 向一个进程发送信号
关于信号
- 信号名称:系统定义,名字或者数字
- 信号含义:系统定义,信号的作用
- 信号的默认处理方法:当一个进程接收到信号时,默认产生的效果
终止进程,暂停进程,忽略发生
e.g.:
- SIGHUP 终端断开
SIGINT ctrl + c
SIGQUIT ctrl + \
SIGTSTP ctrl + z
SIGKILL 终止进程且不能被处理
SIGSTOP 暂停进程且不能被处理
SIGALRM 时钟信号
SIGCHLD 子进程状态改变发给父进程信息号
图例:
python信号处理
- os.kill(pid,sig)
功能:发送一个信号给某个进程
参数:pid 给哪个进程发送信号
sig 要发送什么信号
示例:import os from time import sleep,ctime while True: sleep(2) print(ctime(),os.getpid()) print(ctime(),os.getpid()) #打印结果Tue Aug 14 18:44:04 2018 24844 #------------------------------- import os import signal os.kill(24844,signal.SIGKILL) #24844表示上述示例pid,即可杀死
- signal.alarm(sec)
功能:设置时钟信号,在一定时间后给自身发送SIGALRM信号
参数:sec 时间(秒)
一个进程中只能设置一个时钟,第二个时钟会覆盖之前的时间
程序执行的同步和异步
- 同步 :程序按照步骤一步一步执行,呈现一个先后性和顺序性
- 异步 :程序在执行中利用内核功能帮助完成必要的辅助操作,不影响应用层持续执行
- * 信号是唯一的异步通信方式
- signal.pause()
功能:阻塞等待一个信号的发生
示例:import signal import time #3秒后向自身发送SIGALRM信号 signal.alarm(3) time.sleep(2) signal.alarm(5) #阻塞等待一个信号 #signal.pause() while True: time.sleep(1) print("等待时钟信号...")
- signal.signal(sig,handler)
功能:处理信号
参数:
sig 要处理的信号
handler 信号处理方法
可选值:SIG_DFL 表示使用默认方法处理
SIG_IGN 表示忽略这个信号
func 自定义函数
自定义函数格式:
def func(sig,fram): sig:接收到的信号 frame:信号结构对象
示例:import signal from time import sleep signal.alarm(5) #使用默认的方法处理信号 # signal.signal(signal.SIGALRM,signal.SIG_DFL) # 使用忽略信号的方法处理 signal.signal(signal.SIGALRM,signal.SIG_IGN) signal.signal(signal.SIGINT,signal.SIG_IGN) while True: sleep(2) print("摁ctrl-c") print("等待时钟....") #默认和上述示例一致 #忽略则,你懂得
自定义函数示例:from signal import * import time def handler(sig,frame): if sig == SIGALRM: print("收到时钟信号") elif sig == SIGINT: print("就不结束") alarm(5) signal(SIGALRM,handler) signal(SIGINT,handler) while True: print("Waiting for a signal") time.sleep(2)
*signal函数也是一个异步处理函数,只要执行了该函数,则进程任意时候接收到相应信号都会处理
*signal是不能处理 SIGKILL SIGSTOP的
*父进程中可以用signal(SIGCHLD,SIG_IGN)将子进程的退出交给系统处理
*信号是一种异步的进程间通信方法
信号量
给定一定的数量,对多个进程可见,并且多个进程根据信号量多少确定不同的行为
multiprocessing ---》 Semaphore()
-
sem = Semaphore(num)
功能:生成信号量对象
参数: 信号量的初始值
返回值: 信号量对象sem.acquire() 信号量数量减1 信号量为0时会阻塞
sem.release() 信号量数量加1
sem.get_value() 获取当前信号量的值
示例:
from multiprocessing import Semaphore,Process from time import sleep import os import random #创建信号量对象 初始为3 sem = Semaphore(3) def fun(): print("进程 %d 等待信号量"%os.getpid()) #消耗一个信号量 sem.acquire() print("进程 %d 消耗了1个信号量"%os.getpid()) sleep(random.randint(2,5)) sem.release() print("进程 %d 添加了1个信号量"%os.getpid()) jobs = [] for i in range(4): p = Process(target = fun) jobs.append(p) p.start() for i in jobs: i.join()
同步互斥机制
- 目的 : 解决对共有资源操作产生的争夺
- 临界资源 : 多个进程或者线程都能够操作的资源
- 临界区 : 操作临界资源的代码段
- 同步 : 是一种合作关系,为完成某个任务,多进程或者多线程之间形成一种协调。按照约定依次执行对临界资源的操作,相互告知相互促进。
- 互斥 : 互斥是一种制约关系,当一个进程或者线程进入临界区操作资源时采用上锁的方式,阻止其它进程操作,直到解锁后才会让出资源。
Event 事件
from multiprocessing import Event
- 创建事件对象
e = Event() - 事件阻塞
e.wait([timeout])
功能:使进程处于阻塞状态,直到事件对象被set
- 事件设置
e.set()
功能:让事件对象变为被设置状态 - 清除设置
e.clear()
功能:使事件对象清除设置状态 - 事件判断 判断当前事件对象的状态
e.is_set()
示例:from multiprocessing import Event #创建对象 e = Event() e.set() #设置事件 e.wait(5) print("========================") print(e.is_set()) e.clear() #清除设置状态 e.wait()
示例2:
#ainiin.py from multiprocessing import Process,Event from time import sleep def wait_event(): print('准备操作临界资源') e.wait() print('开始操作临界资源',e.is_set()) def wait_event_timeout(): print('我也要临界资源') e.wait(2) if e.is_set(): print('也开始操作啦') else: print('不行,再等等') e = Event() p1 = Process(target = wait_event) p2 = Process(target = wait_event_timeout) p1.start() p2.start() print('假设你也在做') sleep(3) e.set() print('主进程操作完毕') p1.join() p2.join() #假设你也在做 #准备操作临界资源 #我也要临界资源 #不行,再等等 #主进程操作完毕 #开始操作临界资源 True
示例3:
from multiprocessing import Process,Event from time import sleep def wait_event(file): print("准备操作临界资源") e.wait() print("开始操作临界资源",e.is_set()) fw = open('1.jpg','wb') with open(file,'rb') as f: fw.write(f.read()) def wait_event_timeout(file): print("也想操作临界资源") e.wait(2) if e.is_set(): print("也开始操作临界资源") fw = open('2.jpg','wb') with open(file,'rb') as f: fw.write(f.read()) else: print("等不了了,不等了") e = Event() path = "/home/tarena/file.jpg" file = 'file.jpg' p1 = Process(target = wait_event,args = (file,)) p2 = Process(target = wait_event_timeout,args = (file,)) p1.start() p2.start() print("主进程在操作临界资源") sleep(3) fw = open(file,'wb') with open(path,'rb') as f: fw.write(f.read()) fw.close() e.set() print("主进程操作完毕") p1.join() p2.join()
锁Lock
multiprocessing --》 Lock
- 创建对象
lock = Lock() - lock.acquire() 上锁
- lock.release() 解锁
如果一个锁对象已经被上锁则再调用acquire会阻塞
with lock: 上锁 ... ... 解锁
示例:from multiprocessing import Process,Lock import sys from time import sleep #sys.stdout作为标准输出流是多个进程共有的资源 def writer1(): lock.acquire() #上锁 for i in range(5): sleep(1) sys.stdout.write("writer1输出\n") lock.release() #解锁 def writer2(): with lock: for i in range(5): sleep(1) sys.stdout.write("writer2输出\n") #创建锁 lock = Lock() w1 = Process(target = writer1) w2 = Process(target = writer2) w1.start() w2.start() w1.join() w2.join() #writer1输出 #writer1输出 #writer1输出 #writer1输出 #writer1输出 #writer2输出 #writer2输出 #writer2输出 #writer2输出 #writer2输出 #不加锁则一起打印
多线程
什么是线程
- 线程也是一种多任务编程方式,可以使用计算机的多核资源,线程被称为轻量级的进程
线程特征
- 一个进程可以包含多个线程
- 线程是计算机内核使用的最小单位
- 线程也是一个运行过程,也要消耗计算机资源
- 多个线程共享共用进程的资源
- 线程也有自己的特征属性,TID 指令集,线程栈
- 多个线程之间独立运行互不干扰
- 线程的创建删除消耗的资源要小于进程
threading 模块的使用
- threading.Thread()
功能:创建线程对象
参数:
target 线程函数
name 线程名称 默认Thread-1
args 元组 给线程函数位置传参
kwargs 字典 给线程函数键值传参
返回:线程对象
- t.start() 启动线程
- t.join([timeout]) 回收线程
示例:# woaini.py import threading import os,time #线程函数 a = 1 def music(): global a a = 666 for i in range(5): time.sleep(2) print('播放糊涂挖',os.getpid()) t = threading.Thread(target = music) t.start() for i in range(5): time.sleep(1.5) print('播放篮球高手',os.getpid()) t.join() print(a) #播放篮球高手 17257 #播放糊涂挖 17257 #播放篮球高手 17257 #播放糊涂挖 17257 #播放篮球高手 17257 #播放篮球高手 17257 #播放糊涂挖 17257 #播放篮球高手 17257 #播放糊涂挖 17257 #播放糊涂挖 17257 #666#线程都是一样的pid,所以你懂得结果
线程对象属性
- t.name 线程名称
- t.setName() 设置线程名称
- t.is_alive() 查看线路状态
- threading.currentThread() 获取当前线程对象
示例见:
from threading import Thread,currentThread from time import sleep #线程函数 def fun(sec): print("线程属性测试") sleep(sec) #获取当前线程对象调用getName()获取名称 print("%s 线程结束"%currentThread().getName()) thread = [] for i in range(3): t = Thread(name = "tedu%d"%i,target = fun,\ args = (3,)) thread.append(t) t.start() print(thread[0].is_alive()) thread[1].setName("tarena") #设置线程名称 print(thread[2].name) #获取线程名称 #线程回收 for i in thread: i.join() #线程属性测试 #线程属性测试 #线程属性测试 #True #tedu2 #tarena 线程结束 #tedu2 线程结束 #tedu0 线程结束
- t.daemon 属性
默认情况下主线程结束不会影响分支线程执行
设置为True时,主线程退出则分支线程也退出
- 设置 daemon值
t.setDaemon(True)
t.daemon = True
- 查看daemon值
t.isDaemon()
示例见:from threading import Thread from time import sleep def fun(): sleep(3) print("Daemon测试") t = Thread(target = fun) t.setDaemon(True) # t.daemon = True print(t.isDaemon()) #查看daemon值 t.start() print("======主线程结束======")
创建自己的线程类
步骤:
- 继承Thread类
- 运行Thread类中的__init__方法以获取父类属性
- 重写run方法
示例见:from threading import Thread from time import sleep,ctime class MyThread(Thread): def __init__(self,target,\ name = "Tedu",args = (),kwargs = {}): super().__init__() self.target = target self.name = name self.args = args self.kwargs = kwargs def run(self): self.target(*self.args,**self.kwargs) #线程函数 def player(song,sec): for i in range(2): print("Playing %s : %s"%(song,ctime())) sleep(sec) t = MyThread(target = player,args = ("卡路里",3)) t.start() t.join()
作业
- 复习网络编程tcp udp
- 司机和售票员
- 创建父子进程分别表示司机和售票员
当售票员捕捉到SIGINT信号时,给司机发送SIGUSERI信号,此时司机打印‘老司机来了’
当售票员捕捉到SIGQUIT信号时,给司机发送SIGUSER2信号,此时司机打印‘车速有点快,系好安全带’
当司机捕捉到SIGTSIP信号时,给售票员发送SIGUSER1信号,此时售票员打印‘到站了请下车’ - 到战后,售票员先下车,(子进程先退出) 然后司机下车
解析:import multiprocessing as mp from signal import * import os from time import sleep #子进程出处理信号 def saler_handler(sig,frame): if sig == SIGINT: os.kill(os.getppid(),SIGUSR1) elif sig == SIGQUIT: os.kill(os.getppid(),SIGUSR2) elif sig == SIGUSR1: print("到站了,请下车") os._exit(0) def driver_handler(sig,frame): if sig == SIGUSR1: print("老司机,开车了") elif sig == SIGUSR2: print("车速有点快,系好安全带") elif sig == SIGTSTP: os.kill(p.pid,SIGUSR1) #创建子进程表示售票员 def saler(): signal(SIGINT,saler_handler) signal(SIGQUIT,saler_handler) signal(SIGUSR1,saler_handler) signal(SIGTSTP,SIG_IGN) while True: sleep(2) print("Python 带你去远方看晴空万里") p = mp.Process(target = saler) p.start() signal(SIGUSR1,driver_handler) signal(SIGUSR2,driver_handler) signal(SIGTSTP,driver_handler) signal(SIGINT,SIG_IGN) signal(SIGQUIT,SIG_IGN) p.join()
执行顺序如下: