• 线程控制-延时与守护


    本文解决线程控制的2个场景

    1. 线程延时:延迟一定时间,再执行后续程序

    2. 两个线程,当一个线程执行时间超过规定时间时,执行另一个线程

    场景1:定时器

    具体参考 我的博客 后续会写

    场景2:继承多线程基类

    DelayAction:重写 run 方法,在 run 中延迟

    DelayAction2:重写 run 方法,在 run 中延迟,并获取输出

    class DelayAction(threading.Thread):
        # 延时执行某个函数
        def __init__(self, sec, func, *args):
            threading.Thread.__init__(self)
            self.sec = sec
            self.func = func
            self.args = args
    
        def run(self):
            time.sleep(self.sec)
            apply(self.func, self.args)
    
    
    class DelayAction2(threading.Thread):
        # 延时执行某个函数,并获取返回
        def __init__(self, sec, func, *args):
            threading.Thread.__init__(self)
            self.sec = sec
            self.func = func
            self.args = args
            self.res = None
    
        def run(self):
            time.sleep(self.sec)
            self.res = apply(self.func, self.args)
    
    
    if __name__ == '__main__':
        ### test DelayAction
        def myfunc(x):
            print(x)
            return 1
    
        da = DelayAction(10, myfunc, 222)
        da.start()              # 10s 后打印 222
    
    
        ### test DelayAction2
        da2 = DelayAction2(10, myfunc, 333)
        da2.start()             # 10s 后打印 333
        print(da2.res)          # 马上打出 None ,“打印”这个线程和 da2 是并行的,之所以打印出 None,而不是函数值,因为此时函数还没执行呢
    
        da2.join()
        print(da2.res)          # 带函数执行完毕后,打印出 1

    场景1 和 2:装饰器实现

    timeout:简单例子,方便对比后续

    timeout2:用 定时器延时执行了一个回调函数,然而 被装饰的函数并没有被延时,如果加上 t.join 就实现了延时

    timeout3:解决了这么一种场景:我需要执行一个函数,如果这个函数某个规定时间内没有执行结束,则强制结束,类似 web 中的 wait

      // 这是一个失败的例子在 callback 中 return,并不能使整个函数结束

    timeout4:解决了上述场景,添加了线程守护

    def timeout(func):
        # 被装饰的函数带参数的装饰器
        def myfunc(sec):
            time.sleep(sec)
            func()
        return myfunc
    
    def timeout2(sec, callback):
        # 装饰器带参数的装饰器
        def _deco(func):
            t = threading.Timer(sec, callback)  # threading.Timer定时器,sec 秒后执行回调函数
            t.start()
            t.join()
            def myfunc(arg):                # 注意这里其实并没有延时 myfunc,这只是一个样例,你可以根据需要自己扩展,如在 函数上一行加上 t.join()
                func(arg)
            return myfunc
        return _deco
    
    def timeout3(sec, callback):
        # 有这么一种场景:我需要执行一个函数,如果这个函数某个规定时间内没有执行结束,则强制结束   【这个函数没有实现需求】
        def _deco(func):
            t = threading.Timer(sec, callback)  # callback 假设 10s 结束
            t.start()
            def myfunc():
                func()          # 被装饰的函数 假设 100s 结束
            return myfunc
        return _deco
    
    def timeout4(callback, arg):
        # 有这么一种场景:我需要执行一个函数,如果这个函数某个规定时间内没有执行结束,则强制结束  【这个函数实现了需求】
        def _deco(func):
            t = threading.Thread(target=callback, args=(arg, ))  # callback 假设 10s 结束
            t.setDaemon(True)           ## 必须有, 线程守护,myfunc 相当于主线程
            t.start()
            def myfunc():
                func()          # 被装饰的函数 假设 100s 结束
            return myfunc
        return _deco
    
    
    if __name__ == '__main__':
        ### test timeout
        @timeout
        def test():
            print(33)
    
        # test(10)        # 10s 后打印 33
    
    
        ### test timeout2
        def callback():
            print('callback2')
    
        @timeout2(10, callback)
        def test2(x):
            print(x)
    
        # test2(100)          # 立刻打印出 100, 也就是 test2 立即执行了,并没有被延时
                            # 10s 后打印出 callback2,回调函数延时执行
    
        ## timeout2 中如果加上 t.join,10s 后立即先后打印了 callback2 100,也就是双重延时
    
        ### 注意理解就行,怎么写看实际需求
    
    
        ### test timeout3
        def callback():
            print('callback3')
            return
    
        @timeout3(10, callback)
        def test3():
            time.sleep(100)
            print('test3')
    
        # test3()         # 10s 后打印出 callbak2 callback3,100s 后打印出 test3
    
        ## 这里 test2 并没有执行,为什么打印出 callbak2 callback3,后面我会解释
    
    
        ### test timeout4
        def callback(sec):
            time.sleep(sec)
            print('callback4')
            return
    
        @timeout4(callback, 100)        # 这里是线程守护,10s 的线结束,100s 的自动结束,故主线程是时间短的线程
        def test4():
            time.sleep(10)
            print('test4')
    
        test4()

    注意,时间长的线程被守护。

    这里对装饰器简单总结2点

    1. 装饰器,就是修饰一个函数,所有一定有一层是只输入一个 func

    2. 装饰器首先执行的是装饰的函数 deco,并且 deco 永远是顶层函数     【解决上面 ‘打印出 callbak2 callback3’ 的问题】

    import threading
    
    def timeout2(sec, callback):
        # 装饰器带参数的装饰器
        def _deco(func):
            t = threading.Timer(sec, callback)
            t.start()
            # t.join()
            def myfunc(arg):
                func(arg)
            return myfunc
        return _deco
    
    
    def callback():
            print('callback2')
    
    @timeout2(1, callback)          # 立即打印 callback2,并结束
    def test2(x):
        print(x)

    并没有执行任何函数,而 deco 被自动执行。

    场景2:线程守护简单版

    import time
    import threading
    
    def func1():
        time.sleep(10)
        print('func1')
        return 1
    
    def func2():
        time.sleep(20)
        print('func2')
        return 2
    
    def test():
        t2 = threading.Thread(target=func2)     # 慢的线程,作为守护线程
        t2.setDaemon(True)
        t2.start()
        func1()
    
    
    test()      # 10s 后打印 func1,当快的线程结束时,慢的线程自动结束

    这里可以重写 run 方法,获取 func2 的输出,根据需求自行扩展。

  • 相关阅读:
    【Struts 动态表单】DynaActionForm
    【Struts 分派Action】DispatchAction
    【struts 报错】 No action config found for the specified url
    【Struts APP_PATH】StartSystemListener
    【Struts 编码】
    【Struts 基础案例】
    28. 实现 strStr()
    14. 最长公共前缀
    2. 两数相加
    15. 三数之和
  • 原文地址:https://www.cnblogs.com/yanshw/p/11490876.html
Copyright © 2020-2023  润新知