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