Обновление
В отчете об ошибке запуск на гигантской машине показал, что время восстановления хранилища дерева сократилось с почти 5 часов до примерно 70 секунд:
master:
build time 0:48:53.664428
teardown time 4:58:20.132930
patched:
build time 0:48:08.485639
teardown time 0:01:10.46670
(Предлагаемое исправление)
Вот запрос на извлечение против проекта CPython, который предлагает «исправить это» путем полного удаления запросов.Он отлично работает в моем тестовом случае меньшего размера, в 10 раз, но у меня нет доступа к машине с достаточным объемом оперативной памяти для запуска оригинала.Поэтому я жду кого-то, кто это сделает, прежде чем объединить PR (кто знает? Там может быть более чем одним недостатком дизайна "огромного количества объектов").
Оригинальный ответ
Спасибо за хорошую работу по предоставлению исполняемого образца, воспроизводящего вашу проблему!Увы, я не могу запустить его - требует гораздо больше памяти, чем у меня.Если сократить число строк в десять раз, я получу около 100 000 000 Node
экземпляров в 8 ГБ ОЗУ, и сборке мусора потребуется около 45 секунд, чтобы разрушить дерево (Python 3.7.3).Так что я предполагаю, что у вас есть около миллиарда Node
экземпляров.
Я ожидаю, что вы не получите ответов, потому что здесь нет "общей проблемы", известной здесь, и она требует такой здоровенной машины, чтобы даже попробовать ее,Список рассылки python-dev
может быть лучше задать или открыть вопрос по https://bugs.python.org.
Обычная причина очень медленного сбора мусора в конце цикла - это то, что память выгружается на диски затем "в обычном" порядке считывание объектов в ОЗУ происходит в тысячи раз дольше, чем обычно.Я предполагаю, что здесь не происходит.Если это так, то загрузка ЦП обычно падает почти до 0, поскольку процесс тратит большую часть своего времени на ожидание чтения с диска.
Реже, в реализации malloc / free базовой библиотеки C обнаруживается какой-то плохой шаблон.Но это также кажется маловероятным, поскольку эти объекты настолько малы, что Python запрашивает у C только «большие куски» оперативной памяти и разбивает их на части.
Так что я не знаю.Поскольку ничто не может быть исключено, вы также должны сообщить подробности об используемой ОС и о том, как был построен Python.
Просто для удовольствия, вы можете попробовать это, чтобы получить представление о том, как далеко продвинулись доэто глохнет.Сначала добавьте этот метод к Node
:
def delete(self):
global killed
if self.lo:
self.lo.delete()
self.lo = None
if self.eq:
self.eq.delete()
self.eq = None
if self.hi:
self.hi.delete()
self.hi = None
killed += 1
if killed % 100000 == 0:
print(f"{killed:,} deleted")
В конце train()
добавьте:
tree.root.delete()
И замените вызов на main()
на:
killed = 0
main()
print(killed, "killed")
Что может показывать или не раскрывать что-то интересное.
НЕ ПОДВЕРГАЛСЯ К НЕКОТОМУ ЛЮБОМУ
Я написал об этом сообщение в python-devlist , и один человек пока ответил лично:
Я начал это, используя Python 3.7.3 |упаковано в conda-forge |(по умолчанию, 27 марта 2019 г., 23:01:00) [GCC 7.3.0] :: Anaconda, Inc. на linux
$ python fooz.py
This gets printed!
This doesn't get printed
Требуется ~ 80 ГБ ОЗУи несколько часов, но не застряли.
Так что, если не появится кто-то еще, кто может воспроизвести его, нам, вероятно, здесь не повезло.По крайней мере, вам нужно больше информации о том, какую именно ОС вы используете, и как был построен Python.