Python 개발의 단일 스레드에서 실행되는 여러 예약 작업의 분석 예

黄舟
풀어 주다: 2017-07-27 16:03:23
원래의
1850명이 탐색했습니다.

단일 스레드 다중 시간 작업

1. 초기 버전:

아이디어: 직설적으로 말하면 타이머는 지정된 프로그램의 실행을 지연시키는 것입니다. Python의 타이머는 기능에 도달하지 못하므로 지연된 작업에는 시스템 타이머를 사용해야 하지만 특정 목록에 작동하도록 예약해야 하는 모든 프로그램을 추가하고 다음을 사용하여 프로그램을 제거할 수 있습니다. 목록에서 가장 짧은 타이밍을 실행하고 Bind threading.Timer(시간, 콜백)를 수행하고 시간이 초과될 때까지 기다린 다음 사용자 정의 콜백을 트리거하고 목록에서 방금 가져온 프로그램을 실행한 다음 시간을 업데이트하고 꺼냅니다. 목록에서 가장 짧은 시간을 가진 프로그램을 다시 바인딩하고 새로운 예약된 작업이 목록에 추가되면 연속 반복 루프인 threading.Timer를 계속 바인딩하고 현재 threading.Timer 바인딩을 취소하고 목록의 시간을 업데이트합니다. 다시 가장 짧은 시간을 빼고 threading.Timer를 바인딩합니다...

Code:


import threading
import time

class Timer():
    '''单线程下的定时器'''

    def __init__(self):
        self.queues = []
        self.timer = None
        self.last_time = time.time()

    def start(self):
        item = self.get()
        if item:
            self.timer = threading.Timer(item[0],self.execute)
            self.timer.start()

    def add(self,item):
        print('add',item)
        self.flush_time()
        self.queues.append(item)
        self.queues.sort(key=lambda x:x[0])

        if self.timer:
            self.timer.cancel()
            self.timer = None
        self.start()

    def get(self):
        item = None
        if len(self.queues) > 0:
            item = self.queues[0]
        return item

    def pop(self):
        item = None
        if len(self.queues) > 0:
            item = self.queues.pop(0)
        return item

    def flush_time(self):
        curr_time = time.time()
        for i in self.queues:
            i[0] = i[0] - (curr_time - self.last_time)
        self.last_time = curr_time

    def execute(self):
        # if self.timer:
        #     self.timer.cancel()
        #     self.timer = None
        item = self.pop()
        self.flush_time()
        if item:
            callback = item[1]
            args = item[0]
            callback(args)
        self.start()
로그인 후 복사

실행 및 출력:


if __name__ == '__main__':    # 检测线程数
    def func():        while True:            print(threading.active_count())
            time.sleep(1)
    
    f1 = threading.Thread(target=func)
    f1.start()    
    import logging
    logging.basicConfig(level=logging.INFO,format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %H:%M:%S [%A]")    def func1(*args):
        logging.info('func1 %s'%args)        # time.sleep(5)
    
    def func2(*args):
        logging.info('func2 %s' % args)        # time.sleep(5)
    def func3(*args):
        logging.info('func3 %s' % args)        # time.sleep(5)
    
    def func4(*args):
        logging.info('func4 %s' % args)        # time.sleep(5)
    
    def func5(*args):
        logging.info('func5 %s' % args)        # time.sleep(5)
    
    
    # 测试
    t1 = Timer()
    logging.info('start')
    t1.add([5,func1])
    time.sleep(0.5)
    t1.add([4,func2])
    time.sleep(0.5)
    t1.add([3,func3])
    time.sleep(0.5)
    t1.add([2,func4])
    time.sleep(0.5)
    t1.add([1,func5])
    time.sleep(5)
    t1.add([1,func1])
    t1.add([2,func2])
    t1.add([3,func3])
    t1.add([4,func4])
    t1.add([5,func5])    
    # 输出
    # 2
    # 07/27/2017 10:36:47 [Thursday] start
    # add [5, <function func1 at 0x000000D79FC77E18>]
    # add [4, <function func2 at 0x000000D79FCA8488>]
    # 3
    # add [3, <function func3 at 0x000000D79FCA8510>]
    # add [2, <function func4 at 0x000000D79FCA8598>]
    # 3
    # add [1, <function func5 at 0x000000D79FCA8620>]
    # 3
    # 07/27/2017 10:36:50 [Thursday] func5 1
    # 07/27/2017 10:36:51 [Thursday] func4 0.498349666595459
    # 3
    # 07/27/2017 10:36:51 [Thursday] func3 0.49782633781433105
    # 07/27/2017 10:36:52 [Thursday] func2 0.49848270416259766
    # 3
    # 07/27/2017 10:36:52 [Thursday] func1 0.48449039459228516
    # 2
    # 2
    # add [1, <function func1 at 0x000000D79FC77E18>]
    # add [2, <function func2 at 0x000000D79FCA8488>]
    # add [3, <function func3 at 0x000000D79FCA8510>]
    # add [4, <function func4 at 0x000000D79FCA8598>]
    # add [5, <function func5 at 0x000000D79FCA8620>]
    # 3
    # 07/27/2017 10:36:55 [Thursday] func1 0.9990766048431396
    # 3
    # 07/27/2017 10:36:56 [Thursday] func2 0.9988017082214355
    # 3
    # 07/27/2017 10:36:57 [Thursday] func3 0.99928879737854
    # 07/27/2017 10:36:58 [Thursday] func4 0.9991350173950195
    # 3
    # 3
    # 07/27/2017 10:36:59 [Thursday] func5 0.9988160133361816
로그인 후 복사

Execu 코드

참고: 코드 출력 보기, 모든 타이머가 보정됨 시간은 순차적으로 실행되고 매우 완벽하며 모든 것이 매우 좋아 보이지만 하하하, func에서 time.sleep(5)을 활성화하면 스레드 수가 천천히 증가합니다. 이유는 마지막 타이머 콜백입니다. 아직 실행 중이고 다음 타이머가 시작되었습니다. 아쉽게도 실패했습니다.

2. 수정된 버전입니다. : 생성기-소비자 모델을 사용합니다. threading.Condition 조건 변수가 사용됩니다. 타이머는 강제로 활성화됩니다.

코드:

import time
import threading
import logging

class NewTimer(threading.Thread):
    &#39;&#39;&#39;单线程下的定时器&#39;&#39;&#39;
    def __init__(self):
        super().__init__()
        self.queues = []
        self.timer = None
        self.cond = threading.Condition()

    def run(self):
        while True:
            # print(&#39;NewTimer&#39;,self.queues)
            self.cond.acquire()
            item = self.get()
            callback = None
            if not item:
                logging.info(&#39;NewTimer wait&#39;)
                self.cond.wait()
            elif item[0] <= time.time():
                new_item = self.pop()
                callback = new_item[1]
            else:
                logging.info(&#39;NewTimer start sys timer and wait&#39;)
                self.timer = threading.Timer(item[0]-time.time(),self.execute)
                self.timer.start()
                self.cond.wait()
            self.cond.release()

            if callback:
                callback(item[0])

    def add(self, item):
        # print(&#39;add&#39;, item)
        self.cond.acquire()
        item[0] = item[0] + time.time()
        self.queues.append(item)
        self.queues.sort(key=lambda x: x[0])
        logging.info(&#39;NewTimer add notify&#39;)
        if self.timer:
            self.timer.cancel()
            self.timer = None
        self.cond.notify()
        self.cond.release()

    def pop(self):
        item = None
        if len(self.queues) > 0:
            item = self.queues.pop(0)
        return item

    def get(self):
        item = None
        if len(self.queues) > 0:
            item = self.queues[0]
        return item

    def execute(self):
        logging.info(&#39;NewTimer execute notify&#39;)
        self.cond.acquire()
        self.cond.notify()
        self.cond.release()
로그인 후 복사

실행 및 출력:


if __name__ == &#39;__main__&#39;:    def func():        while True:            print(threading.active_count())
            time.sleep(1)

    f1 = threading.Thread(target=func)
    f1.start()
    logging.basicConfig(level=logging.INFO,format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %H:%M:%S [%A]")

    newtimer = NewTimer()
    newtimer.start()    def func1(*args):
        logging.info(&#39;func1 %s&#39;%args)
        time.sleep(5)    def func2(*args):
        logging.info(&#39;func2 %s&#39; % args)
        time.sleep(5)    def func3(*args):
        logging.info(&#39;func3 %s&#39; % args)
        time.sleep(5)    def func4(*args):
        logging.info(&#39;func4 %s&#39; % args)
        time.sleep(5)    def func5(*args):
        logging.info(&#39;func5 %s&#39; % args)
        time.sleep(5)

    newtimer.add([5,func1])
    newtimer.add([4,func2])
    newtimer.add([3,func3])
    newtimer.add([2,func4])
    newtimer.add([1,func5])
    time.sleep(1)
    newtimer.add([1,func1])
    newtimer.add([2,func2])
    newtimer.add([3,func3])
    newtimer.add([4,func4])
    newtimer.add([5,func5])# 输出# 2# 07/27/2017 11:26:19 [Thursday] NewTimer wait# 07/27/2017 11:26:19 [Thursday] NewTimer add notify# 07/27/2017 11:26:19 [Thursday] NewTimer add notify# 07/27/2017 11:26:19 [Thursday] NewTimer add notify# 07/27/2017 11:26:19 [Thursday] NewTimer add notify# 07/27/2017 11:26:19 [Thursday] NewTimer add notify# 07/27/2017 11:26:19 [Thursday] NewTimer start sys timer and wait# 07/27/2017 11:26:20 [Thursday] NewTimer execute notify# 4# 07/27/2017 11:26:20 [Thursday] func5 1501125980.2175007# 07/27/2017 11:26:20 [Thursday] NewTimer add notify# 07/27/2017 11:26:20 [Thursday] NewTimer add notify# 07/27/2017 11:26:20 [Thursday] NewTimer add notify# 07/27/2017 11:26:20 [Thursday] NewTimer add notify# 07/27/2017 11:26:20 [Thursday] NewTimer add notify# 3# 3# 3# 3# 3# 07/27/2017 11:26:25 [Thursday] func4 1501125981.2175007# 3# 3# 3# 3# 07/27/2017 11:26:30 [Thursday] func1 1501125981.218279# 3# 3# 3# 3# 3# 3# 07/27/2017 11:26:35 [Thursday] func3 1501125982.2175007# 3# 3# 3# 3# 07/27/2017 11:26:40 [Thursday] func2 1501125982.218279# 3# 3# 3# 3# 3# 07/27/2017 11:26:45 [Thursday] func2 1501125983.2175007# 3# 3# 3# 3# 3# 07/27/2017 11:26:50 [Thursday] func3 1501125983.218279# 3# 3# 3# 3# 3# 07/27/2017 11:26:55 [Thursday] func1 1501125984.2175007# 3# 3# 3# 3# 3# 07/27/2017 11:27:00 [Thursday] func4 1501125984.218279# 3# 3# 3# 3# 3# 07/27/2017 11:27:05 [Thursday] func5 1501125985.218279# 3# 3# 3# 3# 3# 07/27/2017 11:27:10 [Thursday] NewTimer wait
로그인 후 복사

출력

참고: 테스트 스레드 수는 이번에도 계속 증가하지 않으며 다중 타이머 작업 요구 사항을 동시에 달성할 수 있습니다. 단점: 두 개의 스레드가 사용됩니다. 구현에 단일 스레드가 사용되지 않습니다. 두 번째 정확도 문제는 프로그램이 계속 실행되기 전에 마지막으로 예약된 프로그램의 실행이 완료될 때까지 기다려야 합니다

위 내용은 Python 개발의 단일 스레드에서 실행되는 여러 예약 작업의 분석 예의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿