Вычисления и кэш
Особенностью скриптового cad является необходимость перезапуска скрипта генерации геометрии при каждом обновлении модели. С ростом размера модели это приводит к значительному росту времени, требующегося на расчёт и отрисовку геометрии. С целью решения этой проблемы вычислительно ёмкие операции ZenCad закешированы и ленифицированы силами библиотеки evalcache.
Вместо непосредственного расчета, evalcache строит дерево построения модели на основе хэшключей генерируемых объектов. Библиотека сохраняет в кэше на жестком диске результаты операций, допускающих кэширование, и в случае, если объект уже был расчитан ранее, достаёт его из кэша. Изменение параметров при следующем запуске скрипта меняет ключи зависимых вычислений.
По умолчанию вычисления отложены (deferred): операции создают граф, а геометрия вычисляется, когда нужна для отображения, экспорта, native() или value(). Кэш помогает повторно использовать результаты одинаковых вычислений, в том числе в новом процессе.
Отладка в условиях работы с ленивыми вычислениями.
Так как evalcache выполняет вычисления только в момент, когда объект в действительности запрошен, а не тогда, когда он объявлен, могут возникать проблемы с пониманием точки возникновения возможной ошибки. Также могут возникать проблемы из-за неявного раскрытия ленивых объектов на некоторых операциях.
Для отладки и понимания точки возникновения ошибки можно в шапке скрипта включить немедленные вычисления. Публичные типы объектов при этом не меняются:
import zencad as z
z.configure(cache_enabled=False)
z.set_evaluation_mode("immediate")
body = z.box(20) - z.cylinder(3, 20)
assert isinstance(body, z.Shape)
z.set_evaluation_mode("deferred")
Режим действует до явного изменения и не меняет типы объектов. Переключение не вычисляет все уже созданные выражения. Кэш независим от режима: его отключение само по себе не отключает ленивые вычисления.
| Режим | cache_enabled=False |
cache_enabled=True |
|---|---|---|
immediate |
Операция вычисляется сразу, без чтения и записи дискового кэша. | Результат запрашивается сразу: берётся из дискового кэша, а при отсутствии вычисляется и сохраняется. |
deferred |
Операция вычисляется, когда нужен результат, без чтения и записи дискового кэша. | Когда результат понадобится, он берётся из дискового кэша, а при отсутствии вычисляется и сохраняется. |
configure(cache_enabled=False) отключает чтение и запись дискового кэша, но не удаляет его файлы. Уже вычисленные результаты объектов могут повторно использоваться в памяти. Таблица описывает операции, допускающие кэширование; простые значения могут вычисляться при построении графа.
Общий дисковый кэш
По умолчанию все процессы ZenCad текущего пользователя используют один общий
каталог tempfile.gettempdir()/zencad-cache-
Путь и состояние кэша можно изменить в окне настроек ZenCad. Приоритет настроек: явный configure() в процессе, затем ZENCAD_CACHE_DIR/ZENCAD_CACHE_DISABLE, затем сохранённые пользовательские настройки.
import zencad as z
z.configure(cache_dir="./model-cache", cache_enabled=True)
body = z.box(5)
print(body.mass().value())
ZENCAD_CACHE_DISABLE=1 отключает чтение и запись дискового кэша. z.clear_cache() явно очищает настроенный кэш; в обычном скрипте вызывать его не требуется.
Диагностика без редактора
zencad inspect model.py --eager --no-cache --json
zencad inspect model.py --tree
zencad inspect model.py --tree --failed-path
Заголовок скрипта может переопределить начальный режим runner. Граф показывает зависимости, cache hit и ошибки. Командная строка.
Для интеграций доступен явный владелец вычислений: context = z.Context.deferred(cache=False) и context.call(z.box, 10). У Context нет CAD-фасада; для обычных скриптов отдельный контекст не нужен. Старые настройки zencad.lazy описаны в руководстве миграции.