线程控制-延时与守护

时间:2019-09-09
本文章向大家介绍线程控制-延时与守护,主要包括线程控制-延时与守护使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本文解决线程控制的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 的输出,根据需求自行扩展。

原文地址:https://www.cnblogs.com/yanshw/p/11490876.html