python 信号.同步 day07

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("======主线程结束======")

创建自己的线程类

  步骤:

  1. 继承Thread类
  2. 运行Thread类中的__init__方法以获取父类属性
  3. 重写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()

作业

  1. 复习网络编程tcp udp
  2. 司机和售票员
  • 创建父子进程分别表示司机和售票员
    当售票员捕捉到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()
    

猜你喜欢

转载自blog.csdn.net/qq_42584444/article/details/81661155
今日推荐