zoukankan      html  css  js  c++  java
  • python 信号量,Event, 定时器

    信号量

    信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行。

    如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群路人争抢公共厕所,公共厕所有多个坑位,这意味着同一时间可以有多个人上公共厕所,但公共厕所容纳的人数是一定的,这便是信号量的大小。

    from threading import Thread,Semaphore,current_thread
    import time,random
    
    
    sm = Semaphore(3)  # 设置信号量为3,即同时会有3个任务会抢到锁
    
    def task():
            sm.acquire()
            print("%s acquire task" %current_thread().getName())
            time.sleep(random.randint(1,3))
            sm.release()
            print("-------- %s release task 
    " % current_thread().getName())
    
    if __name__ == '__main__':
        for i in range(10):
            t = Thread(target=task)
            t.start()
    
    ------------输出------------
    Thread-1 acquire task
    Thread-2 acquire task
    Thread-3 acquire task
    -------- Thread-1 release task 
    
    -------- Thread-3 release task 
    Thread-4 acquire task
    Thread-5 acquire task
    
    -------- Thread-5 release task 
    
    -------- Thread-2 release task 
    
    Thread-7 acquire task
    Thread-6 acquire task
    -------- Thread-7 release task 
    Thread-8 acquire task
    
    -------- Thread-4 release task 
    
    Thread-9 acquire task
    -------- Thread-6 release task 
    
    Thread-10 acquire task
    -------- Thread-8 release task 
    
    -------- Thread-9 release task 
    
    -------- Thread-10 release task 
    

     原理 

    1. Semaphore管理一个内置的计数器
    2. 每当调用acquire()时内置计数器-1
    3. 调用release() 时内置计数器+1
    4. 计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()

    Event

    线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。

    为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。

    在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。

    一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行

    from threading import Event
    Event.isSet() #返回event的状态值
    Event.wait() #如果 event.isSet()==False将阻塞线程;
    Event.set() #设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
    Event.clear() #恢复
    

     例如,有多个工作线程尝试链接MySQL,我们想要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,如果连接不成功,

    都会去尝试重新连接。那么我们就可以采用threading.Event机制来协调各个工作线程的连接操作

    from threading import currentThread, Thread,Event
    import time
    
    event = Event()
    
    def conn_mysql():
        "连接mysql"
        count = 1
        while not event.is_set():
            # 当没有检测到时候
            if count > 3:  # 如果尝试次数大于3,就主动抛异
                raise ConnectionError('尝试链接的次数过多')
    
            print('%s 第%s次尝试' % (currentThread(), count))
    
            event.wait(timeout=1)  # 等待检测(里面的参数是超时1秒)
    
            count += 1
    
            print('%s 开始链接...' % (currentThread().getName()))
    
    
    def check_mysql():
        ''' 检测数据库'''
        print('%s 检测mysql...' % (currentThread().getName()))
        time.sleep(2)
        event.set()
    
    if __name__ == '__main__':
        for i in range(3):
            t = Thread(target=conn_mysql)
            t.start()
    
        t = Thread(target=check_mysql)
        t.start()
    
    ----输出------
    <Thread(Thread-1, started 7860)> 第1次尝试
    <Thread(Thread-2, started 2816)> 第1次尝试
    <Thread(Thread-3, started 8188)> 第1次尝试
    Thread-4 检测mysql...
    Thread-2 开始链接...
    Thread-1 开始链接...
    <Thread(Thread-1, started 7860)> 第2次尝试
    Thread-3 开始链接...
    <Thread(Thread-3, started 8188)> 第2次尝试
    <Thread(Thread-2, started 2816)> 第2次尝试
    Thread-1 开始链接...
    Thread-3 开始链接...
    Thread-2 开始链接...
    

      

    定时器

    定时器,指定n秒后执行某操作

    from threading import Timer
    
    def task(name):
        print('hell0 %s' % name)
    
    t = Timer(5,task,args=('egon',))
    t.start()
    

      

    验证码输入

    from threading import Timer
    import random
    
    class Code(object):
        def __init__(self):
            self.make_cache()
    
    
        def make_cache(self,interval=10):
            self.cache = self.make_code()
            print("验证码:", self.cache)
            self.t = Timer(interval, self.make_cache)  # 每过5s执行一次
            self.t.start()
    
        def make_code(self,n=4):
            res = ''
            for i in range(n):
                s1 = str(random.randint(0,9))
                s2 = chr(random.randint(65,90))
                res += random.choice([s1,s2])
            return res
    
        def check_code(self):
            while True:
                code = input("请输入验证码>> ").strip()
                if code.upper() == self.cache:
                    print('验证码输入正确!')
                    self.t.cancel()
                    break
    obj = Code()
    obj.check_code()
    

      

  • 相关阅读:
    镜像源收集
    关于vue-cli3脚手架安装后回退到vue-cli2版本的问题
    window.location 对象
    常用正则表达式
    前端开发工程师面试题
    面试题1
    Echarts.js使用
    swipe.js 使用方法
    canvas基础API
    前端面试题集锦
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/9484788.html
Copyright © 2011-2022 走看看