86 votes

Pourquoi les classes de machines asynchrones État (et pas les structs) à Roslyn ?

Prenons l'exemple très simple de la méthode async:

static async Task myMethodAsync() 
{
    await Task.Delay(500);
}

Quand je compile ce avec VS2013 (pré-compilateur Roslyn) générés de machine d'état est une struct.

private struct <myMethodAsync>d__0 : IAsyncStateMachine
{  
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

Quand je le compile avec VS2015 (Roslyn) le code généré est ceci:

private sealed class <myMethodAsync>d__1 : IAsyncStateMachine
{
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

Comme vous pouvez le voir Roslyn génère une classe (et non pas une structure (struct). Si je me souviens bien de la première mise en application de la async/await soutien dans l'ancien compilateur (CTP2012 je suppose) a également généré des classes, puis il a été changé à la structure de raisons de performances. (dans certains cas, vous pouvez éviter complètement de boxe et de tas d'allocation...) (Voir ceci)

Personne ne sait pourquoi il a changé de nouveau dans Roslyn? (Je n'ai pas de problème à ce sujet, je sais que ce changement est transparent et ne change pas le comportement de n'importe quel code, je suis juste curieux)

Edit:

La réponse de @Damien_The_Unbeliever (et le code source :) ) à mon humble avis explique tout. Le comportement décrit de Roslyn s'applique uniquement pour la version debug (et c'est nécessaire à cause de la CLR restriction mentionnée dans le commentaire). Dans le Communiqué il génère également un struct (avec tous les avantages que..). Si cela semble être une solution intelligente pour soutenir à la fois de Modifier et de Continuer et de meilleures performances dans la production. Intéressant, merci pour tous ceux qui ont participé!

110voto

Damien_The_Unbeliever Points 102139

Je n'ai pas connaissance de cela, mais depuis Roslyn est open-source, ces jours-ci, nous pouvons aller à la chasse dans le code pour une explication.

Et ici, sur la ligne 60 de la AsyncRewriter, nous trouvons:

// The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class.
var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct;

Ainsi, tandis que il ya certains d'appel à l'aide d' structs, la grande victoire de permettre de Modifier et de Continuer à travailler au sein d' async méthodes a évidemment été choisi comme la meilleure option.

3voto

Luaan Points 8934

Il est difficile de donner une réponse définitive pour quelque chose comme ça (à moins que quelqu'un de l'équipe du compilateur gouttes :)), mais il ya quelques points que vous pouvez envisager:

Le rendement "prime" des structs est toujours un compromis. Fondamentalement, vous obtenez le résultat suivant:

  • La valeur sémantique
  • Pile Possible (peut-être même registre?) l'allocation
  • En évitant d'indirection

Qu'est-ce que cela signifie dans l'attendent cas? Eh bien, en fait... rien. Il n'y a qu'une très courte période de temps pendant laquelle la machine d'état est sur la pile - rappelez-vous, await efficacement un return, de sorte que la méthode de la pile meurt; l'état de la machine doivent être conservés quelque part, et ce "quelque part" est certainement sur le tas. Pile la durée de vie ne convient pas de code asynchrone bien :)

En dehors de cela, la machine de l'etat viole quelques bonnes lignes directrices pour la définition des structures:

  • structs doit être au plus de 16 octets - l'état de la machine contient deux pointeurs, qui, sur leur propre remplissez le 16 octets limite proprement sur un système 64 bits. En dehors de cela, il y a l'état lui-même, de sorte qu'il va au-dessus de la "limite". Ce n'est pas une grosse affaire, car il est tout à fait probable que jamais passés par référence, mais notez la façon qui ne correspond pas exactement le cas d'utilisation de structures - une structure (struct), c'est essentiellement un type de référence.
  • structs doit être immuable - eh bien, cela n'a probablement pas besoin de beaucoup de commentaires. C'est une machine d'état. Encore une fois, ce n'est pas une grosse affaire, car la structure est auto-générée le code et le privé, mais...
  • structs devrait logiquement représenter une valeur unique. Certainement pas le cas ici, mais que déjà le genre de suit de disposer d'une mutable état en premier lieu.
  • Il ne devrait pas être encadrées, souvent pas un problème ici, puisque nous l'utilisons les génériques partout. L'état est, en définitive, quelque part sur le tas, mais au moins, c'est de ne pas être enfermé dans une boîte (automatique). Encore une fois, le fait qu'il est utilisé uniquement en interne c'est assez bien vide.

Et bien sûr, tout cela est dans un cas où il n'y a pas de fermetures. Lorsque vous avez des habitants (ou des champs) qui traversent l' awaits, l'état est plus gonflé, ce qui limite l'utilité de l'aide d'une struct.

Compte tenu de tout cela, la classe approche est nettement plus propre, et je ne serais pas s'attendre à une notable augmentation des performances de l'utilisation de l' struct à la place. Tous les objets en cause sont similaires à vie, de sorte que le seul moyen d'améliorer les performances de la mémoire serait de faire tous les d'entre eux structs (stocker dans la mémoire tampon, par exemple), ce qui est impossible dans le cas général, bien sûr. Et la plupart des cas où vous l'auriez await en premier lieu (c'est-à-asynchronous I/O travail) impliquent déjà dans d'autres classes - par exemple, les données des tampons, des cordes... C'est assez peu probable que vous await quelque chose qui renvoie simplement 42 , sans faire de tas d'allocations.

En fin de compte, je dirais que le seul endroit où tu aimerais vraiment voir une réelle différence de performance serait de repères. Et de l'optimisation de critères de référence est une idée stupide, pour dire le moins...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X