12Fermer14
GoldenCrystalLe 20/08/2016 à 23:58
./11 > Bah en gros justement, le problème que j'exprime c'est que dans le combo C#/CLR actuel, async et lambdas soient du "sucre syntaxique", si on peut apeller ça comme ça pour une fonctionnalité si grosse: En pratique, le code généré par la réécriture en state machine est juste impossible à faire par un humain lambda. (On peut concevoir le système une fois, on peut le comprendre, donc le généraliser (ce qui a été fait), mais on peut pas le faire manuellement à chaque fois).

Aujourd'hui, si tu écris une une méthode A qui ne fait qu'apeller une méthode B avec certains paramètres, le JIT en aura connaissance, et va inliner ton appel de méthode. Maintenant, si tu procèdes de même avec une méthode async, ça ne va pas être aussi simple. Rien que le fait que le code généré contienne un try/catch va causer de gros problèmes: on n'a en théorie "pas le droit" d'optimiser ce genre de choses car ça rend le stack trace erroné, même si dans ce cas, ça n'a aucune importance. Au final, tu vas te retrouver à créer deux belles grosses machines à états, quand une seule t'aurait suffi. (Déjà ça produit un overhead au niveau du code généré, significativement plus lourd, mais ça aura un impact au runtime non négligeable si le code est utilisé souvent)

Pour l'histoire des delegate donc je parlais, c'est un truc plus con, mais tu dis au JIT de créer un delegate, il va créer un objet (il ne peut en théorie pas avoir de connaissance absolue sur l'objet qu'il va créer), et si tu crées ton delegate sur un objet "closure" que le compilateur C# a décidé de créer bien qu'il eut pu faire sans, ben le JIT n'aura pas la capacité de le détecter. Y'a un moment où tu as perdu l'information vitale (que la closure servait à rien), et l'information a été perdue dans le compilateur C#.

C'est pas vraiment théorique et anectodique: Si tout le monde écrit du code qui génère ce genre de comportements (après tout, ouais, c'est "pas très grave"), bah au niveau du monde entier, tu as consommé n*x cycles CPU en trop chaque minutes, et tu as dépensés je ne sais combien de kWh à cause de ce phénomène. Et crois moi, on génère tous ce genre de code à un moment où un autre où on ne fait pas attention. (Je l'ai vu faire chez mes collègues, je l'ai lu dans des codes sur internet, je suis tombé dans le truc plusieurs fois. Et c'est vraiment con, parce que c'est le genre de trucs où tu ne devrais pas te poser de questions: la façon "simple" dont tu écris ton code ne devrait rien changer… Mais ça change.)

C'est le même principe que d'écrire du code pas forcément trop optimisé dans ton programme. En soi, ça gêne pas s'il n'y a pas de problèmes de performances. Mais si tu fais une lib, destinée à être utilisée par d'autres, ça gêne toujours. C'est simple: ton code n'est peut-être "pas beaucoup utilisé" par chaque programme dans le monde, mais peut-être que chaque programme est beaucoup utilisé. Au global, tu fais perdre au monde de la performance.
(C'est pour ça que ta bibliothèque de classes et ta chaîne d'outils de compilation doit toujours être au top de la perfection pour le code qui sera utilisé souvent "en général". Et les petits gars de .NET appliquent en général bien ce concept.)

./12 > En pratique, en mode débogage, VS a besoin de plein d'informations pour une raison x ou y, et le compilateur C# va générer de l'IL qui facilitera la vie au débogueur, avec la coopération du JIT, qui générera de l'assembleur qui facilitera la vie au débogueur (optimisations minimales). Dans ce cas là, je vois mal pourquoi, mais c'est difficile de dire. Si ton code généré en "release" est bon, alors c'est bon.

(Sinon, tu as avancé sur tes bugs étranges de code dynamique ? ^^)