Python 为什么禁用标准日志记录模块时速度如此之慢?

Python 为什么禁用标准日志记录模块时速度如此之慢?,python,python-3.x,logging,printf,Python,Python 3.x,Logging,Printf,我做了这个基准测试: 导入日志 导入副本 输入pstats 导入cProfile 从io导入StringIO def差异(第一个统计数据、第二个统计数据): first_stats=copy.deepcopy(first_stats) 第一个\u stats.total\u调用-=第二个\u stats.total\u调用 第一次_stats.prim_调用-=第二次_stats.prim_调用 第一个统计数据.total\u tt-=第二个统计数据.total\u tt first_set=s

我做了这个基准测试:

导入日志
导入副本
输入pstats
导入cProfile
从io导入StringIO
def差异(第一个统计数据、第二个统计数据):
first_stats=copy.deepcopy(first_stats)
第一个\u stats.total\u调用-=第二个\u stats.total\u调用
第一次_stats.prim_调用-=第二次_stats.prim_调用
第一个统计数据.total\u tt-=第二个统计数据.total\u tt
first_set=set(first_stats.stats.keys())
second_set=set(second_stats.stats.keys())
交叉点=第一个集合。交叉点(第二个集合)
对于交叉点中的func:
first_source=first_stats.stats[func]
second_source=second_stats.stats[func]
第一个呼叫中心、第一个呼叫中心、第一个呼叫中心、第一个呼叫中心,呼叫者=第一个呼叫源
第二个呼叫中心,第二个呼叫中心,第二个呼叫中心,第二个呼叫中心,呼叫者=第二个呼叫源
first_stats.stats[func]=(第一次抄送第二次抄送,第一次抄送第二次抄送,第一次抄送第二次抄送,第一次抄送第二次抄送,第一次抄送第二次抄送,呼叫者)
对于func,第二个_stats.stats.items()中的源:
如果func不在first_stats.stats中:
func=列表(func)
func[0]='*'+func[0]
func=元组(func)
first_stats.stats[func]=源
返回第一个属性
def打印差异(统计数据):
输出\u流=StringIO()
stats.stream=输出流
stats.sort_stats(“时间”)
stats.print_stats()
返回输出\u stream.getvalue()
def平均值(统计数据、平均计数):
stats.total_calls/=平均_计数
stats.prim_调用/=平均_计数
stats.total_tt/=平均计数
对于func,源位于stats.stats.items()中:
cc、nc、tt、ct、呼叫者=源
stats.stats[func]=(cc/average\u计数、nc/average\u计数、tt/average\u计数、ct/average\u计数、呼叫者)
返回数据
def profile_something(profile_函数、平均计数、迭代计数):
输出\u流=StringIO()
探查器状态=pstats.Stats(流=输出流)
对于范围内的索引(平均计数):
profiler=cProfile.Profile()
profiler.enable()
配置文件\函数(迭代次数\计数)
profiler.disable()
探查器_status.add(探查器)
打印('Profiled','{0:7.3f}'。格式(profiler_status.total_tt),'seconds at','%3d'(索引+1),
'for',profile\函数。\名称\刷新=真)
平均值(探查器状态、平均计数)
探查器\u status.sort\u stats(“时间”)
探查器_status.print_stats()
返回“\n%s的配置文件结果”%(配置文件\u函数。\u名称\u,输出\u流.getvalue()),配置文件\u状态
def run_评测(第一个_函数、第二个_函数、平均_计数、迭代次数_计数):
第一个函数结果,第一个函数统计=profile某物(第一个函数,平均数,迭代数)
第二个函数结果,第二个函数统计=profile某物(第二个函数,平均数,迭代数)
总差异=打印差异(差异(第一个功能统计、第二个功能统计))
时间差=第一个函数统计值总值-第二个函数统计值总值
输出=2500
输出\u流=StringIO()
打印(第一个函数\u结果[0:输出],文件=输出\u流)
打印('\n',第二个函数\u结果[0:输出],文件=输出\u流)
打印('\n\n总差异\n',总差异[0:输出],文件=输出流)
返回((时间差、第一个函数统计、总计、第二个函数统计、总计、,
第一个函数。第二个函数。第二个函数。格式(迭代次数,,,d'),
输出\u stream.getvalue())
def get_logging_debug():
logging.Logger.manager.loggerDict.clear()
log=logging.getLogger(“基准”)
如果不是log.hasHandlers():
date_format=“%H:%M:%S”
string_format=“%(asctime)s:%(毫秒)010.6f-%(name)s.%(funcName)s:%(行号)d-%(消息)s”
stream=logging.StreamHandler()
格式化程序=logging.formatter(字符串格式、日期格式)
stream.setFormatter(格式化程序)
log.addHandler(流)
返回日志
def日志记录\修改\日志\调试\关闭(迭代次数\计数):
log=get_logging_debug()
log.setLevel(“警告”)
对于范围内的索引(迭代次数计数):
log.debug('Message')
def标准日志\u快速调试\u关闭(迭代次数\u计数):
类名称(对象):
def_uuuinit_uuu(self,is_debug):
self.is_debug=is_debug
调试器=类名(False)
对于范围内的索引(迭代次数计数):
如果debugger.u为调试:
打印(‘消息’)
结果=[]
追加(运行评测(standardlog\u fastdebug\u off,logging\u mod\u log\u debug\u off,1100000))
打印('\n\n结果详细信息:')
对于索引,结果为enumerate(结果,开始=1):
打印(“\n%2d.%s\n”%(索引,结果[1]))
打印('结果恢复:')
对于索引,结果为enumerate(结果,开始=1):
打印(“%2d.%10.5f%10.5f%10.5f%s-%s=%s迭代次数“((索引,)+结果[0]))
这将在我的计算机上产生以下结果:

$ python3.7.3 benchmark_tests.py
Profiled   0.910 seconds at   1 for standardlog_fastdebug_off
Profiled  10.450 seconds at   1 for logging_mod_log_debug_off


Results details:

 1.
 Profile results for standardlog_fastdebug_off
         5.0 function calls in 0.910 seconds

   Ordered by: internal time

      ncalls     tottime     percall     cumtime     percall filename:lineno(function)
         1.0       0.910       0.910       0.910       0.910 benchmark_tests.py:150(standardlog_fastdebug_off)
         1.0       0.000       0.000       0.000       0.000 {built-in method builtins.__build_class__}
         1.0       0.000       0.000       0.000       0.000 benchmark_tests.py:152(ClassName)
         1.0       0.000       0.000       0.000       0.000 benchmark_tests.py:154(__init__)
         1.0       0.000       0.000       0.000       0.000 {method 'disable' of '_lsprof.Profiler' objects}





 Profile results for logging_mod_log_debug_off
         20,000,058.0 function calls in 10.450 seconds

   Ordered by: internal time

      ncalls     tottime     percall     cumtime     percall filename:lineno(function)
         1.0       4.157       4.157      10.450      10.450 benchmark_tests.py:143(logging_mod_log_debug_off)
10,000,000.0       3.968       0.000       6.293       0.000 F:\Python\lib\logging\__init__.py:1362(debug)
10,000,000.0       2.325       0.000       2.325       0.000 F:\Python\lib\logging\__init__.py:1620(isEnabledFor)
         1.0       0.000       0.000       0.000       0.000 benchmark_tests.py:129(get_loggging_debug)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:1222(getLogger)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:1342(__init__)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:1310(_clear_cache)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\threading.py:75(RLock)
         5.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:212(_acquireLock)
         3.0       0.000       0.000       0.000       0.000 {method 'clear' of 'dict' objects}
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:794(_addHandlerRef)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:813(__init__)
         5.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:221(_releaseLock)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:1355(setLevel)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:513(__init__)
         3.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:187(_checkLevel)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:842(createLock)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:1273(_fixupParents)
         5.0       0.000       0.000       0.000       0.000 {method 'acquire' of '_thread.RLock' objects}
         2.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__.py:727(__init__)
         1.0       0.000       0.000       0.000       0.000 F:\Python\lib\logging\__init__


Total difference
          -20,000,053.0 function calls in -9.540 seconds

   Ordered by: internal time

      ncalls     tottime     percall     cumtime     percall filename:lineno(function)
         1.0       4.157       4.157      10.450      10.450 * benchmark_tests.py:143(logging_mod_log_debug_off)
10,000,000.0       3.968       0.000       6.293       0.000 * F:\Python\lib\logging\__init__.py:1362(debug)
10,000,000.0       2.325       0.000       2.325       0.000 * F:\Python\lib\logging\__init__.py:1620(isEnabledFor)
         1.0       0.910       0.910       0.910       0.910 benchmark_tests.py:150(standardlog_fastdebug_off)
         1.0       0.000       0.000       0.000       0.000 * benchmark_tests.py:129(get_loggging_debug)
         1.0       0.000       0.000       0.000       0.000 {built-in method builtins.__build_class__}
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:1222(getLogger)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:1342(__init__)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:1310(_clear_cache)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\threading.py:75(RLock)
         5.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:212(_acquireLock)
         3.0       0.000       0.000       0.000       0.000 * ~:0(<method 'clear' of 'dict' objects>)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:794(_addHandlerRef)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:813(__init__)
         5.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:221(_releaseLock)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:1355(setLevel)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:513(__init__)
         3.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:187(_checkLevel)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:842(createLock)
         1.0       0.000       0.000       0.000       0.000 * F:\Python\lib\logging\__init__.py:1273(_fixupParents)
         5.0       0.000       0.000       0.000       0.000 * ~:0(<method 'acquire' of '_thread.R


Results resume:
 1.   -9.53998    0.91016   10.45015  standardlog_fastdebug_off - logging_mod_log_debug_off  = 10,000,000 iterations
$python3.7.3 benchmark\u tests.py
为standardlog_fastdebug_off在1时设定了0.910秒
在1时配置了10.450秒,用于记录\u mod\u log\u debug\u off
结果详情:
1.
standardlog_fastdebug_关闭的配置文件结果
0.910秒内完成5.0次函数调用
订购人:内部时间
ncalls tottime percall cumtime percall文件名:lineno(函数)
1.0 0.910 0.910 0.910 0.910 0.910基准测试。py:150(标准日志快速调试关闭)
1.0 0.000 0.000 0.000 0.000{内置方法内置。\uuuuu build\u class\uuuu}
1.0 0.000 0.000 0.000 0.000基准测试。py:152(类名)
1.0 0.000 0.000 0.000 0.000 0.000基准测试。py:154(初始)
1.0 0.000 0.000 0.000 0.000{方法'disable'of''lsprof.Profiler'objects}
日志记录的配置文件结果\u mod\u log\u debug\u off
20,000,058.0
class A:
    def __init__(self):
        self.a = False
        self.a_b = B()

class B:
    def __init__(self):
        self.b = False
        self.b_c = C()

class C:
    def __init__(self):
        self.c = False

import time
N = 10_000_000
a = A()

def f_0(N):
    start = time.time()
    for dummy in range(N):
        if False:
            print(111)  # never printed
    stop = time.time()
    return stop - start

def f_1(N):
    start = time.time()
    for dummy in range(N):
        if a.a:
            print(111)
    stop = time.time()
    return stop - start

def f_2(N):
    start = time.time()
    for dummy in range(N):
        if a.a_b.b:
            print(111)
    stop = time.time()
    return stop - start

def f_3(N):
    start = time.time()
    for dummy in range(N):
        if a.a_b.b_c.c:
            print(111)
    stop = time.time()
    return stop - start

result = {'x': list(), 'y': list()}
for run in range(10):
    for x, f in enumerate([f_0, f_1, f_2, f_3]):
        result['x'].append(str(x))
        result['y'].append(f(N))
    print(run)

import matplotlib.pyplot as plt
plt.figure()
plt.plot(result['x'], result['y'], '.')
plt.xlabel('argument access chain length')
plt.ylabel('time, seconds')
plt.show()
import logging
import argparse
import time
import sys


log = logging.getLogger("blep")


def prepare_off():
    pass


def prepare_on():
    logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)


def step(x):
    log.info("now running step %s", x)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("-n", type=int, default=500_000)
    ap.add_argument(
        "--mode", required=True, choices=("off", "on")
    )
    args = ap.parse_args()

    prepare = globals()[f"prepare_{args.mode}"]

    prepare()
    t0 = time.perf_counter_ns()
    for x in range(args.n):
        step(x)
    t1 = time.perf_counter_ns()
    print(
        vars(args),
        (t1 - t0) / args.n,
        "ns/iter",
        file=sys.stderr,
    )


if __name__ == "__main__":
    main()
$ time python3 so54470102.py --mode off >/dev/null
{'n': 500000, 'mode': 'off'} 541.53571 ns/iter
        0.32 real         0.30 user         0.01 sys
$ time python3 so54470102.py --mode on >/dev/null
{'n': 500000, 'mode': 'on'} 26932.005352 ns/iter
       13.52 real        13.01 user         0.47 sys
$ time python3 -m cProfile -o /dev/null so54470102.py --mode on >/dev/null
{'n': 500000, 'mode': 'on'} 45733.711544 ns/iter
       22.93 real        22.23 user         0.57 sys
$ time python3 -m cProfile -o /dev/null so54470102.py --mode off >/dev/null
{'n': 500000, 'mode': 'off'} 962.122468 ns/iter
        0.54 real         0.52 user         0.01 sys