Что такое реальные примеры графа зависимостей Gradle?

Как отмечено в документации, Gradle использует направленный граф без петель (DAG) для создания графа зависимостей. От моего понимания, имея отдельные циклы для оценки и выполнения основная функция для инструмента сборки. например, документ Gradle указывает, что это активирует некоторые опции, которые иначе были бы невозможны.

Я интересуюсь реальными примерами, которые иллюстрируют питание этой функции. Каковы некоторые примеры использования, для которых граф зависимостей важен? Я особенно интересуюсь персональными историями от поля, ли с Gradle или столь же оборудованным инструментом.

Я делаю эту 'общественную Wiki' с самого начала, поскольку будет трудно оценить 'корректный' ответ.

9
задан Michael Easter 9 March 2010 в 17:17
поделиться

2 ответа

Этот провокационный вопрос послужил поводом для того, чтобы наконец заглянуть в Gradle. Я до сих пор не использовал его, поэтому могу предложить только анализ, отмеченный при просмотре документов, а не личные истории.

Мой первый вопрос заключался в том, почему граф зависимостей задач Gradle гарантированно является ациклическим. Я не нашел на это ответа, но противоположный случай легко построить, поэтому я предполагаю, что обнаружение цикла - это проверка, которая запускается при построении графа, и сборка завершается неудачно до выполнения первой задачи, если существуют незаконные циклические зависимости. Без предварительного построения графика это состояние сбоя может не быть обнаружено до тех пор, пока построение не будет почти завершено. Кроме того, процедура обнаружения должна была бы запускаться после выполнения каждой задачи, что было бы очень неэффективно (пока граф строился поэтапно и был доступен глобально, поиск в глубину потребовался бы только для поиска начальной точки, а затем оценка цикла потребует минимальной работы, но общая работа все равно будет больше, чем выполнение однократного сокращения всего набора отношений вначале). Я бы назвал раннее обнаружение основным преимуществом.

Зависимость задач может быть ленивой (см. 4.3 Зависимости задач и связанный пример в 13.14). Зависимости ленивых задач не могут быть правильно оценены, пока не будет построен весь граф. То же самое верно и для транзитивного (не связанного с задачами) разрешения зависимостей, которое может вызвать бесчисленные проблемы и потребовать повторных перекомпиляций по мере обнаружения и разрешения дополнительных зависимостей (также требующих повторных запросов к репозиторию). Функция правил задач (13.8) тоже было бы невозможно. Эти проблемы и, вероятно, многие другие могут быть обобщены, если учесть, что Gradle использует динамический язык и может динамически добавлять и изменять задачи, поэтому до оценки первого прохода результаты могут быть недетерминированными, поскольку путь выполнения построен и изменяются во время выполнения, поэтому разные последовательности оценки могут давать произвольно разные результаты, если есть зависимости или поведенческие директивы, которые неизвестны до более позднего времени, потому что они еще не были созданы. (Возможно, это стоит изучить на некоторых конкретных примерах. Если это правда, то даже двух проходов не всегда будет достаточно. Если A -> B, B -> C, где C изменяет поведение A так, что он больше не зависит от B, тогда у вас есть проблема. Я надеюсь, что есть некоторые передовые практики по ограничению метапрограммирования нелокальной областью видимости, чтобы не допускать его в произвольных задачах. Интересным примером может быть симуляция парадокса путешествий во времени, когда внук убивает своего деда или женится на бабушке, наглядно демонстрируя некоторые практические этические принципы!)

Это может улучшить состояние и отчеты о ходе выполнения текущей сборки. TaskExecutionListener обеспечивает перехватчики до и после обработки каждой задачи, но, не зная количества оставшихся задач, он мало что может сказать о статусе, кроме «6 задач выполнены. О выполнении задачи foo». Вместо этого вы можете инициализировать TaskExecutionListener с количеством задач в gradle.taskGraph.whenReady, а затем присоединить его к TaskExecutionGraph.Теперь он может предоставлять информацию для включения деталей отчета, таких как «6 из 72 задач выполнено. Выполняется задача foo. Расчетное оставшееся время: 2 часа 38 минут». Это было бы полезно для отображения на консоли для сервера непрерывной интеграции, или если Gradle использовался для оркестровки большой многопроектной сборки, и оценки времени имели решающее значение.

Как указал Джерри Буллард, оценочная часть жизненного цикла имеет решающее значение для определения плана выполнения, который предоставляет информацию о среде, поскольку среда частично определяется контекстом выполнения (пример 4.15 в разделе «Настройка с помощью группы DAG»). ). Вдобавок я заметил, что это полезно для оптимизации выполнения. Независимые подпути можно безопасно передавать разным потокам. Алгоритмы обхода для выполнения могут потребовать меньше памяти, если они не наивны (моя интуиция подсказывает, что постоянный переход по пути с наибольшим количеством подпути приведет к большему стеку, чем всегда предпочтение путей с наименьшим количеством подпутей).

Интересным использованием этого может быть ситуация, когда многие компоненты системы изначально отключены для поддержки демонстраций и инкрементальной разработки. Затем во время разработки, вместо обновления конфигурации сборки по мере реализации каждого компонента, сама сборка может определить, готов ли подпроект для включения (возможно, он пытается захватить код, скомпилировать его и запустить заранее определенный набор тестов) . Если это так, этап оценки обнаружит это, и соответствующие задачи будут включены, в противном случае он выберет задачи для заглушек.Возможно, существует зависимость от базы данных Oracle, которая пока недоступна, а вы пока используете встроенную базу данных. Вы можете позволить сборке проверять доступность, прозрачно переключаться, когда это возможно,и скажу вам, что он переключил базы данных, а не вы. В этом направлении может быть множество творческих применений.

Gradle выглядит потрясающе. Спасибо за провокацию исследования!

6
ответ дан 3 November 2019 в 01:55
поделиться

Пример из той же документации иллюстрирует мощь этого подхода:

Как мы подробно опишем позже {{1 }} (См. Главу 30, Жизненный цикл сборки) Gradle имеет этап конфигурации и этап выполнения. После фазы настройки Gradle знает все задачи, которые должны быть выполнены. Gradle предлагает вам ловушку для использования этой информации. Примером использования для этого может быть проверка, является ли задача выпуска частью задач, которые должны быть выполнены. В зависимости от этого вы можете назначить разные значения для некоторых переменных.

Другими словами, вы можете подключиться к процессу сборки на раннем этапе, чтобы при необходимости изменить его ход. Если некоторые фактические работы по сборке уже были выполнены, возможно, уже слишком поздно что-то менять.

3
ответ дан 3 November 2019 в 01:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: