【问题标题】:Alternative to global variables when logging stats about requests记录有关请求的统计信息时替代全局变量
【发布时间】:2022-01-06 17:15:16
【问题描述】:

我有一个程序可以记录一些关于我下载的数据的消息。除此之外,我想显示一些关于我对站点发出的每个 k 请求的请求的统计信息(在我的情况下,k 是 10)+ 执行结束时的一些总体统计信息。

目前我有一个我不满意的实现,因为它使用全局变量。我正在寻找更清洁的替代品。它看起来像这样(注意:请忽略我使用print 而不是logging 并且我使用time.time 而不是time.perf_counter 来衡量时间流逝的事实(请阅读此处,后者将是更好的选择):

import time
import pprint

def f2(*args, **kwargs):
    global START_TIME

    global NO_REQUESTS
    global TOTAL_TIME_FOR_REQUESTS
    global MAX_TIME_FOR_REQUEST
    global AVERAGE_TIME_FOR_REQUESTS

    global TOTAL_TIME_FOR_DECODING
    global TOTAL_TIME_FOR_INTERSECT
    
    # ... logic that changes values of most of these global variables

    if NO_REQUESTS % 10 == 0:
        AVERAGE_TIME_FOR_REQUESTS = TOTAL_TIME_FOR_REQUESTS / NO_REQUESTS
        print()
        print('no requests so far: ' + str(NO_REQUESTS))
        print('average request time: {:.2f}s'.format(AVERAGE_TIME_FOR_REQUESTS))
        print('max request time: {:.2f}s'.format(MAX_TIME_FOR_REQUEST))
                    
        elapsed = time.time() - START_TIME
        hours_elapsed = elapsed // 3600
        minutes_elapsed = (elapsed % 3600) // 60
        seconds_elapsed = ((elapsed % 3600) % 60)
        print('time elapsed so far: {}h {}m {:.2f}s'.format(hours_elapsed, minutes_elapsed, seconds_elapsed))
        print()

        time5 = time.time()
        decoded = some_module.decode(res.content)
        time6 = time.time()

        elapsed2 = time6 - time5
        TOTAL_TIME_FOR_DECODING += elapsed2

    return something


def f1(*args, **kwargs):

    global START_TIME

    global TOTAL_TIME_FOR_REQUESTS
    TOTAL_TIME_FOR_REQUESTS = 0
    global MAX_TIME_FOR_REQUEST
    MAX_TIME_FOR_REQUEST = 0
    global NO_REQUESTS
    NO_REQUESTS = 0
    global AVERAGE_TIME_FOR_REQUESTS
    AVERAGE_TIME_FOR_REQUESTS = 0

    global TOTAL_TIME_FOR_DECODING
    TOTAL_TIME_FOR_DECODING = 0
    global TOTAL_TIME_FOR_INTERSECT
    TOTAL_TIME_FOR_INTERSECT = 0

    f2() # notice call to other function!

    # ... some logic
        
    return some_results


def output_final_stats(elapsed, results, precision='{:.3f}'):
    print()
    print('=============================')

    hours_elapsed = elapsed // 3600
    minutes_elapsed = (elapsed % 3600) // 60
    seconds_elapsed = ((elapsed % 3600) % 60)
    print("TIME ELAPSED: {:.3f}s OR {}h {}m {:.3f}s".format(
        elapsed, hours_elapsed, minutes_elapsed, seconds_elapsed))

    print("out of which:")
    # print((precision+'s for requests)'.format(TOTAL_TIME_FOR_REQUESTS)))
    print('{:.3f}s for requests'.format(TOTAL_TIME_FOR_REQUESTS))
    print('{:.3f}s for decoding'.format(TOTAL_TIME_FOR_DECODING))
    print('{:.3f}s for intersect'.format(TOTAL_TIME_FOR_INTERSECT))

    total = TOTAL_TIME_FOR_REQUESTS + TOTAL_TIME_FOR_DECODING + TOTAL_TIME_FOR_INTERSECT
    print('EXPECTED: {:.3f}s'.format(total))
    print('DIFF: {:.3f}s'.format(elapsed - total))
    print()
    print('AVERAGE REQUEST TIME: {:.3f}s'.format(AVERAGE_TIME_FOR_REQUESTS))
    print('TOTAL NO. REQUESTS: ' + str(NO_REQUESTS))
    print('MAX REQUEST TIME: {:.3f}s'.format(MAX_TIME_FOR_REQUEST))
    print('TOTAL NO. RESULTS: ' + str(len(results)))
    pprint('RESULTS: {}'.format(results), indent=4)


if __name__ == '__main__':

    START_TIME = time.time()
    results = f1(some_params)
    final_time = time.time()

    elapsed = final_time - START_TIME
    output_final_stats(elapsed, results)


我想到的方式(不确定是否是最佳选择,对替代方案开放)是以某种方式在 NO_REQUESTS 变量上设置一个侦听器,每当该数字达到 10 的倍数时,就会触发我记录的变量我很感兴趣。但是,我会将这些变量存储在哪里,它们的命名空间是什么?

另一种选择可能是为我的一个函数设置一个参数化装饰器,但在这种情况下,我不确定将我感兴趣的值从一个函数传递到另一个函数有多容易。

【问题讨论】:

    标签: python logging time python-requests global-variables


    【解决方案1】:

    我认为最简洁的方法是使用参数化的类装饰器。

    class LogEveryN:
        def __init__(self, n=10):
            self.n = n
            self.number_of_requests = 0
            self.total_time_for_requests = 0
            self.max_time_for_request = 0
            self.average_time_for_request = 0
    
        def __call__(self, func, *args, **kwargs):
            def wrapper(*args, **kwargs):
                self.number_of_request += 1
    
                if self.number_of_request % self.n:
                    # Do your computation and logging
    
                return func(*args, **kwargs)
            return wrapper
    
    @LogEveryN(n=5)
    def request_function():
        pass
    

    【讨论】:

    • 非常感谢!我会试一试的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多