Malgré son caractère haute performance et son utilisation sur des superordinateurs, Julia n'atteint pas toujours ses promesses à ce niveau. Notamment, un problème récurrent est celui du temps nécessaire pour afficher un premier graphique à l'aide du paquet Plots.jl, le plus répandu, mais aussi le plus lent. Impoarter ce paquet et lancer la première commande de dessin prend énormément de temps, au moins une dizaine de secondes sur des machines puissantes : la situation ne correspond pas au niveau de performance souhaité par les concepteurs du langage.
Après des débats houleux et longs, un chercheur a analysé la source de ce problème de performance : le temps d'inférence, au niveau du compilateur Julia, c'est-à-dire la partie qui cherche à attribuer les types les plus précis possibles aux variables, afin d'accélérer un maximum l'exécution du programme par la suite (bon nombre de gens pensaient, avant, que le problème était surtout dû à LLVM, le compilateur utilisé par après pour générer du code optimisé). Or, vu la structure du paquet, avec un chargement dynamique des moteurs de rendu, il serait très difficile de proposer une nouvelle version de Plots.jl qui ne souffre pas de ce défaut. Certains choix de conception peuvent être améliorés sur ce point de vue. Par exemple, Plots.jl stocke les paramètres dans des dictionnaires, mais avec des types particuliers : alors que Julia est livré avec une série de méthodes pour les dictionnaires précompilées, ce choix de type rend le code précompilé inutile.

Par conséquent, la meilleure chose à faire est d'améliorer l'implémentation de Julia pour résoudre ce problème, surtout qu'il n'est pas limité à Plots.jl : les paquets OrdinaryDiffEq.jl et StochasticDiffEq.jl, utiles pour la résolution d'équations différentielles, rencontrent une variante proche.

Les développeurs de Julia pensent depuis longtemps à inclure un interpréteur dans leur implémentation, de telle sorte que seul le code qui est souvent exécuté est compilé et optimisé (on parle de JIT ou de compilation juste à temps) : la JVM ou encore les moteurs JavaScript de Firefox et de Chrome fonctionnent de la sorte, mais ont fait une transition inverse (passer d'un interpréteur pur à un compilateur à la demande). Un interpréteur écrit en Julia (bien évidemment !) est en cours de développement depuis quelques mois : en fait, JuliaInterpreter.jl est aussi utile pour la conception des moteurs de débogage. Le problème venant de la compilation, le code qui cause ces lenteurs serait d'abord interprété (sans coût a priori) ; ensuite, il serait petit à petit compilé, en fonction des besoins et de la fréquence d'utilisation du code.

Cette solution ne serait pas si facile à implémenter, car un moteur JIT ne peut fonctionner que sur des fonctions : si on remarque, en plein milieu d'une boucle, qu'il faudrait vraiment songer à la compiler, on ne peut le faire qu'avant le prochain appel de la fonction qui contient cette boucle. Si le code est écrit en une seule fonction, il n'y a aucun moyen facile d'optimiser cette boucle. Certes, ce code contrevient aux meilleures pratiques en Julia (écrire de petites fonctions très spécifiques, qui peuvent être facilement optimisées), il n'empêche que tous les utilisateurs ne suivent pas cette règle. Les solutions à mettre en œuvre sont à l'étude depuis février.

En tout état de cause, JuliaInterpreter.jl n'est pas encore apte à prendre en charge une partie aussi critique de l'implémentation du langage, puisque le code n'est pas encore prévu pour la performance : il était d'abord prévu pour du débogage, où la performance n'est pas l'aspect le plus critique.

Ensuite, les développeurs envisagent un deuxième axe d'action, focalisé sur le compilateur. En effet, plus le code passe rapidement par le compilateur (plutôt que par un JIT), plus l'exécution sera rapide. Les solutions envisagées consistent à adapter plus finement certaines heuristiques dans le code ou encore à améliorer les structures de données pour la recherche des méthodes à appeler dans certains cas spécifiques mais courants. Aussi, l'inférence de type se perd parfois dans une longue chaîne d'appels où aucune inférence n'est possible : il est proposé d'utiliser une profondeur maximale pour effectuer cette inférence dans les cas où le compilateur estime probable qu'il ne trouvera jamais de type précis. L'aspect le plus simple pourrait cependant être de stocker les résultats des inférences effectuées lors de la précompilation d'un paquet, ce qui permettrait de n'effectuer ces calculs qu'une seule fois par paquet (et pas une fois par chargement de Julia).