簡體   English   中英

循環中打印語句的限制速率

[英]Limit Rate of Print statements in Loop

我正在尋找一種有效的方法來限制 while 循環中打印語句的執行速率。 我有一個 while 循環,其中包含許多日志記錄語句,這些語句的執行取決於系統當時正在做什么(記錄錯誤消息等)。 我試圖限制每個日志語句的執行,以便如果檢測到錯誤,它不會在每次循環時記錄警告。 我不想只記錄一次錯誤,系統必須以設定的時間間隔記錄錯誤,直到不再檢測到錯誤。

我目前擁有的一個例子是:

while True:
  if True:                                  #Detect Error 1
    print("Print Every Second")             #Log error 1
  if True:                                  #Detect Error 2
    print("Print Every 10 Seconds")         #Log error 2

如果錯誤檢查驗證為 True,則每次循環運行時都會記錄錯誤。 我希望能夠限制 Logging 語句的執行速率。

我能夠使用以下代碼創建概念證明:

import time

def RateLimited(interval):
    def wrapper(func):
        wrapper.lastTimeCalled = [0.0]
        def rateLimitedFunction(*args,**kargs):
            rateLimitedFunction.elapsed = time.time() - wrapper.lastTimeCalled[0]
            rateLimitedFunction.leftToWait = wrapper.minInterval - rateLimitedFunction.elapsed
            if rateLimitedFunction.leftToWait>0:
                pass
            else:
              wrapper.lastTimeCalled[0] = time.time()
              return func(*args,**kargs)
        return rateLimitedFunction
    wrapper.minInterval = interval
    return wrapper

@RateLimited(1)    #Function can be run 60 times per minute (Every Second)
def Print1():
    print("Print Every Second")

@RateLimited(10)     #Function can be run 6 times per minute (Every 10 Seconds)
def Print2():
    print("Print Every 10 Seconds")

if __name__ == "__main__":
    while True:
        Print1()
        Print2()

這需要一個新的 function 用於必須在循環之外定義的每個打印語句。 如果可能的話,我寧願在一行中使用類似於以下語法的東西:

rateLimit("Print Every Second", 1, id=1)
rateLimit("Print Every 10 Seconds", 10, id=2)

也許看看threading 模塊 您可以設置打印隊列並繼續處理其他內容。

一個粗略的例子:

import threading 
import time 
from collections import deque 

class Printq:
  def __init__(self, initial=[], t=2):
    self.q=deque(initial)
    self.t=t
    threading.Timer(self.t, self.pq).start()
    
  def pq(self):
    if self.q:
      print(self.q.popleft())
    
    if self.q:
      threading.Timer(self.t, self.pq).start()
      
  def add(self, item):
    self.q.append(item)
    
q=Printq(list('123'))

while q.q:
  print("processing")
  time.sleep(1)

印刷:

processing
processing
1
processing
processing
2
processing
processing
processing
3

您可以同時擁有多個不同時間的 Printq:

q1=Printq(list('1234'))
q2=Printq([e*100 for e in range(1,6)],1)

while q1.q or q2.q:
  print("processing")
  time.sleep(1)

印刷:

processing
processing
100
1
processing
200
processing
300
2
processing
400
processing
500
3
processing
processing
4

這是基於我的評論的一種方法。 它設置了一個Logger class ,它將每 N 秒打印一次set的內容(為了唯一性)。 log方法附加到消息堆棧:

from threading import Timer
import time

class Logger():
    def __init__(self, timeout=3):
        self.timeout = timeout
        self.msgs = set()
        self._timer = None
        self.start()

    def start(self):
        self._timer = Timer(self.timeout, self.run)
        self._timer.start()

    def run(self):
        self.start()
        print(self.msgs)
        self.msgs = set()
        # Restart timer

    def log(self, msg):
        self.msgs.add(msg)

    def stop(self):
        self._timer.cancel()


# start the log timer function
logger = Logger()

# Log something every second
for i in range(12):
  # Log a recurring message
  logger.log("msg")
  # Log a unique message
  logger.log(i)
  time.sleep(1)

logger.stop()

output

{'msg', 0, 1, 2}
{'msg', 3, 4, 5}
{'msg', 6, 7, 8}
{'msg', 9, 10, 11}

為了滿足您最初的需求,我會嘗試構建一個標記記錄器:

  • 每條消息都將與一個標簽相關聯
  • 每個標簽都會有一個靜默超時,以防止它在成功記錄后的延遲期間實際記錄消息

我會用一個配置字典來實現它,將每個標簽名稱映射到以秒為單位的延遲,以及每個標簽的當前字典記錄下一條允許消息的時間是多少。

代碼可以是:

import time

class LimitedLogger:
    def __init__(self, /, **kwargs):
        for delta in kwargs.values():
            if delta < 0:
                raise ValueError("Tag values must be positive")
        self.conf = dict(kwargs.items())
        self.curr = dict()
        
    def log(self, tag, msg):
        if tag not in self.conf:
            raise ValueError(f'Tag {tag} is unknown')
        t = time.time()
        if tag not in self.curr:
            self._do_log(tag, msg, t)
        else:
            min_t = self.curr[tag]
            if t >= min_t:
                # actually print or log
                self._do_log(tag, msg, t)
    def _do_log(self, tag, msg, t):
        print(msg)
        self.curr[tag] = t + self.conf[tag]

    # optionaly removed passed timeouts from curr
    def clean(self):
        t = time.time()
        self.curr = {k: v for k, v in self.curr if v > t}

    # optionaly allow calls like log.err(msg)
    def __getattr__(self, name):
        if name not in self.conf:
            raise AttributeError(f'{LimitedLogger} has no attribute {name}')
        return lambda msg: self.log(name, msg)

使用示例:

lg = LimitedLogger(warn=10, err=5)
while True:
    lg.err('Err')
    lg.warn('Warn')

    
Err        <-- immediate
Warn
Err        <-- after 5 seconds
Err        <-- after 10 seconds
Warn
Err        <-- after 15 seconds
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM