線程控制-延時與守護


本文解決線程控制的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 的輸出,根據需求自行擴展。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM