Quels sont des exemples du monde réel de graphe de dépendance de Gradle?

StackOverflow https://stackoverflow.com/questions/2414281

  •  19-09-2019
  •  | 
  •  

Question

Comme indiqué dans la documentation , Gradle utilise un graphe orienté acyclique (DAG) pour construire un graphe de dépendance. De ma compréhension, ayant des cycles distincts pour l'évaluation et l'exécution est un élément important pour un outil de construction. par exemple. Gradle doc indique que cela permet à certaines caractéristiques qui seraient autrement impossibles.

Je suis intéressé par des exemples concrets qui illustrent la puissance de cette fonctionnalité. Quels sont les cas d'utilisation pour lesquels un graphe de dépendance est important? Je suis particulièrement intéressé par des histoires personnelles sur le terrain, que ce soit avec Gradle ou un outil équipé de la même.

Je fais ce « wiki communautaire » dès le départ, car il sera difficile d'évaluer une réponse « correcte ».

Était-ce utile?

La solution

Cette question provocatrice à condition de motivation pour la recherche enfin dans Gradle. Je n'ai pas encore utilisé, donc je ne peux offrir l'analyse noté tout en parcourant les documents, pas des histoires personnelles.

Ma première question est pourquoi un graphe de dépendance des tâches Gradle est garantie acyclique. Je ne trouve pas la réponse à cette question, mais un cas contraire facile à construire, donc je suppose que la détection de cycle est une validation qui est exécuté lorsque le graphique est construit et la construction échoue avant l'exécution de la première tâche si il existe des dépendances cycliques illégales. Sans construire d'abord le graphique, cette condition d'échec pourrait ne pas être découvert jusqu'à ce que la construction est presque terminée. En outre, la routine de détection devrait courir après chaque tâche a été exécutée, ce qui serait très inefficace (tant que le graphique a été construit progressivement et disponible dans le monde, une recherche en profondeur d'abord ne serait nécessaire de trouver un point de départ, et après les évaluations du cycle nécessiteraient un minimum de travail, mais le travail total serait encore supérieur à faire une seule réduction sur tout l'ensemble des relations au départ). Je craie la détection précoce comme un avantage majeur.

Une dépendance de tâche peut être paresseux (voir: 4.3 Les dépendances de tâches, et un exemple lié à 13,14). dépendances de tâches Lazy ne peuvent pas être évalués correctement jusqu'à ce que le graphe entier est construit. La même chose est vraie pour transitive (non-tâche) résolution de dépendance, ce qui pourrait causer d'innombrables problèmes, et nécessitent recompilation répétées comme des dépendances supplémentaires sont découverts et résolus (nécessitant également des demandes répétées à un dépôt). Les règles de travail fonction (13.8) ne serait pas possible non plus. Ces questions, et probablement beaucoup d'autres, peuvent être généralisés en considérant que Gradle utilise un langage dynamique, et peut dynamiquement ajouter et modifier des tâches, donc avant une évaluation de premier passage, les résultats pourraient être non-déterministe puisque le chemin d'exécution est construit et modifié lors de l'exécution, ainsi, différentes séquences d'évaluation pourrait produire des résultats différents de façon arbitraire s'il y a des dépendances ou des directives de comportement qui ne sont pas connus plus tard, parce qu'ils ont pas encore été créé. (Cela peut être digne d'enquêter sur des exemples concrets S'il est vrai, alors même deux passes ne seraient pas toujours suffisante Si A -..> B, B -> C, où C modifie le comportement de A pour ne plus dépend de B, alors vous avez un problème. J'espère qu'il ya des meilleures pratiques en matière de restriction metaprogramming avec une portée non locale, de ne pas permettre dans les tâches arbitraires. un exemple amusant serait une simulation d'un paradoxe de Voyage dans le temps, où un petit-enfant tue son grand-père ou sa grand-mère épouse, illustrant vivement des principes éthiques pratiques!)

Il peut permettre à un meilleur état et les rapports d'étape sur un cours d'exécution construction. Un TaskExecutionListener offre avant / après des crochets au traitement de chaque tâche, mais sans connaître le nombre de tâches restantes, il n'y a pas grand-chose qu'il pourrait dire au sujet de statut autre que « 6 tâches terminées. A propos d'exécuter la tâche foo. » Au lieu de cela, vous pouvez initialiser un TaskExecutionListener avec le nombre de tâches dans gradle.taskGraph.whenReady, puis le joindre à la TaskExecutionGraph. Maintenant, il pourrait fournir des informations pour permettre les détails du rapport comme « 6 de 72 tâches terminées maintenant exécuter la tâche foo Temps restant estimé:.. 2h 38m. » Ce serait utile d'afficher sur une console pour un serveur d'intégration continue, ou si Gradle était utilisé pour orchestrer une grande estimations de construction et de temps à plusieurs projets ont été cruciales.

Comme le souligne Jerry Bullard, la partie d'évaluation du cycle de vie est essentielle pour la détermination du plan d'exécution, qui fournit des informations sur l'environnement, car l'environnement est en partie déterminée par le contexte d'exécution (Exemple 4,15 dans la configuration de l'article DAG ). De plus, je pouvais voir ce qui est utile pour l'optimisation de l'exécution. independent sous-chemins pourraient être en toute sécurité aux fils différents. algorithmes de marche pour l'exécution peut être moins gourmandes en mémoire si elles ne sont pas naïfs (mon intuition dit que la marche toujours le chemin le plus de sous-chemins va conduire à une pile plus grande que préférant toujours les chemins avec les moins) sous-chemins.

Une utilisation intéressante de cela pourrait être une situation où de nombreux composants d'un système sont d'abord pour soutenir sur liftée démos et développement progressif. Ensuite, au cours du développement, plutôt que de mettre à jour la configuration de construction que chaque composant devient mis en œuvre, la construction elle-même pourrait déterminer si un sous-projet est encore prêt pour l'inclusion (peut-être il tente de saisir le code, le compiler et exécuter une suite de tests pré-déterminé) . Dans ce cas, la phase d'évaluation révélerait cela, et les tâches appropriées seraient inclus, sinon, il sélectionne les tâches pour les talons. Peut-être il y a une dépendance sur une base de données Oracle qui ne sont pas encore disponibles, et vous utilisez une base de données intégrée dans l'intervalle. Vous pouvez laisser construire vérifier la disponibilité, basculer en toute transparence sur le moment où il peut, et vous dire que les bases de données en marche, plutôt que de vous raconter. Il pourrait y avoir beaucoup d'utilisations créatives le long de ces lignes.

Gradle semble impressionnant. Merci d'avoir provoqué des recherches!

Autres conseils

de la même documentation illustre la puissance de cette approche:

  

Comme nous décrivons en détail plus tard   (Voir le chapitre 30, Cycle de vie de construction)   Gradle a une phase de configuration et   une phase d'exécution. Après le   phase de configuration Gradle connaît tous   les tâches qui doivent être exécutées. gradle   vous offre un crochet pour faire usage de cette   information. Un cas d'utilisation pour cela   être de vérifier si la tâche de libération est   une partie des tâches à exécuter.   En fonction de ce que vous pouvez assigner   différentes valeurs à certaines variables.

En d'autres termes, vous pouvez brancher dans le processus de construction au début, de sorte que vous pouvez modifier son cours au besoin. Si des travaux de construction réelle avait déjà été effectué, il peut être trop tard pour changer.

J'évaluer les différents systèmes de construction maintenant et avec gradle je réussi à ajouter du code laid qui énumère toutes les tâches de type « pot » et les change donc, que chaque manifeste jar comprend l'attribut « Build-Number » (qui est utilisé plus tard pour composer les noms de fichier final):

gradle.taskGraph.whenReady {
    taskGraph ->
    taskGraph.getAllTasks().findAll {
        it instanceof org.gradle.api.tasks.bundling.Jar
    }.each {
        it.getManifest().getAttributes().put('Build-Number', project.buildVersion.buildNumber)
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top