У меня есть приложение, которое требует инициализации большого количества объектов с помощью Python (3.5.2) и иногда сталкивается с некоторыми замедлениями.
Замедление происходит при определенной инициализации: большинство вызовов __init__
длятся менее 1 нс, но один из них иногда длится несколько десятков секунд.
Я смог воспроизвести это с помощью следующего фрагмента, который инициализирует 500k простого объекта.
import cProfile
class A:
def __init__(self):
pass
cProfile.run('[A() for _ in range(500000)]')
Я запускаю этот код в блокноте. В большинстве случаев (9/10) этот код выводит следующее (нормальное выполнение)
500004 function calls in 0.675 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
500000 0.031 0.000 0.031 0.000 <ipython-input-5-634b77609653>:2(__init__)
1 0.627 0.627 0.657 0.657 <string>:1(<listcomp>)
1 0.018 0.018 0.675 0.675 <string>:1(<module>)
1 0.000 0.000 0.675 0.675 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
В другое время выводит следующее (медленное выполнение)
500004 function calls in 40.154 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
500000 0.031 0.000 0.031 0.000 <ipython-input-74-634b77609653>:2(__init__)
1 40.110 40.110 40.140 40.140 <string>:1(<listcomp>)
1 0.014 0.014 40.154 40.154 <string>:1(<module>)
1 0.000 0.000 40.154 40.154 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
При использовании tqdm цикл, похоже, застрял на одной итерации. Важно отметить, что я смог воспроизвести это в ноутбуке с уже выделенным объемом памяти.
Я подозреваю, что это происходит из списка ссылок на объекты, используемые сборщиком мусора, которые могут время от времени копироваться.
Что именно здесь происходит, и есть ли способы избежать этого?