Est-il une limite au nombre de imbriquée "pour" les boucles?
comme tout a une limite, je me demandais s'il y avait une limite au nombre de boucles for
imbriquées ou aussi longtemps que j'ai de la mémoire, je peux les ajouter, le compilateur Visual Studio peut-il créer un tel programme?
bien sûr, une boucle for
imbriquée de 64 ou plus ne serait pas pratique à déboguer, mais est-ce faisable?
private void TestForLoop()
{
for (int a = 0; a < 4; a++)
{
for (int b = 0; b < 56; b++)
{
for (int c = 0; c < 196; c++)
{
//etc....
}
}
}
}
4 réponses
je prends des risques en postant ceci, mais je pense que la réponse est:
entre 550 et 575
avec paramètres par défaut dans Visual Studio 2015
j'ai créé un petit programme qui génère des boucles for
imbriquées...
for (int i0=0; i0<10; i0++)
{
for (int i1=0; i1<10; i1++)
{
...
...
for (int i573=0; i573<10; i573++)
{
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
}
...
...
}
}
pour 500 boucles imbriquées, le programme peut encore être compilé. Avec 575 boucles, le compilateur renflouent:
Avertissement AD0001 Analyseur de 'Microsoft.CodeAnalysis.CSharp.Diagnostic.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticanalyzer "a lancé une exception du système de type".InsufficientExecutionStackException 'with message' pile insuffisante pour continuer à exécuter le programme en toute sécurité. Cela peut se produire en ayant trop de fonctions sur la pile d'appels ou de fonctions sur la pile en utilisant trop d'espace sur la pile.'.
avec le message de compilateur sous-jacent
erreur CS8078: une expression est trop longue ou complexe pour compiler
bien sûr, il s'agit d'un résultat purement hypothétique . Si la boucle la plus interne fait plus qu'un Console.WriteLine
, alors moins de boucles imbriquées peuvent être possibles avant que la taille de la pile soit dépassée. Aussi, cela peut ne pas être strictement technique limite, dans le sens qu'il peut être caché paramètres de augmenter la taille maximale de la pile pour l ' "analyseur" mentionné dans le message d'erreur, ou (si nécessaire) pour l'exécutable résultant. Cette partie de la réponse, cependant, est laissée aux personnes qui connaissent C# en profondeur.
mise à Jour
en réponse à la question dans les commentaires :
je serais intéressé de voir cette réponse étendue pour "prouver" expérimentalement si vous pouvez mettre 575 variables locales sur la pile si elles sont et non utilisées dans les for-loops, et/ou si vous pouvez mettre 575 non imbriquées for-loops dans une seule fonction
Pour les deux cas, la réponse est: Oui, c'est possible. Lors du remplissage de la méthode avec 575 déclarations auto-générées
int i0=0;
Console.WriteLine(i0);
int i1=0;
Console.WriteLine(i1);
...
int i574=0;
Console.WriteLine(i574);
il peut encore être compilé. Tout le reste ne m'aurait surpris. La taille de la pile requise pour les variables int
n'est que de 2,3 KB. Mais j'étais curieux, et pour tester d'autres limites, j'ai augmenté ce nombre. Finalement, il a fait pas compiler, causant l'erreur
erreur CS0204: seuls 65534 locaux, y compris ceux générés par le compilateur, sont autorisés
, qui est un point intéressant, mais qui a déjà été observé ailleurs: nombre Maximum de variables dans la méthode
de même, 575 Non emboîtés for
- boucles, comme dans
for (int i0=0; i0<10; i0++)
{
Console.WriteLine(i0);
}
for (int i1=0; i1<10; i1++)
{
Console.WriteLine(i1);
}
...
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
peut aussi être compilé. Ici, j'ai aussi essayé de trouver la limite, et a créé plus de ces boucles. En particulier, je n'étais pas sûr que les variables de boucle dans ce cas compte aussi "locaux", parce qu'ils sont dans leur propre { block }
. Mais encore, plus de 65534 n'est pas possible. Enfin, j'ai ajouté un test composé de 40000 boucles du modèle
for (int i39999 = 0; i39999 < 10; i39999++)
{
int j = 0;
Console.WriteLine(j + i39999);
}
qui contenait une variable supplémentaire dans la boucle, mais ceux-ci semblent compter comme" locaux " aussi, et il n'a pas été possible de compiler cela.
pour résumer: la limite de ~550 est en effet causée par la profondeur de nidification des boucles. Cela a également été indiqué par le message d'erreur
erreur CS8078: une expression est trop longue ou complexe pour compiler
le documentation d'erreur CS1647 malheureusement (mais compréhensible) ne spécifie pas une "mesure" de la complexité, mais donne seulement le conseil pragmatique
il y avait un débordement de pile dans le compilateur traitant votre code. Pour corriger cette erreur, simplifiez votre code.
pour souligner encore ceci: pour le cas particulier des boucles for
profondément imbriquées, tout cela est plutôt académique et hypothétique . Mais la recherche sur le web pour le message D'erreur de CS1647 révèle plusieurs cas où cette erreur est apparue pour du code qui n'était probablement pas intentionnellement complexe, mais créé dans des scénarios réalistes.
il n'y a pas de limite stricte dans la spécification linguistique C# ni dans le CLR. Votre code serait itératif, plutôt que récursif, ce qui pourrait conduire à un débordement de la pile assez rapide.
il y a quelques choses qui pourraient compter comme un seuil, par exemple le compteur (généralement) int
que vous utiliseriez, qui attribuerait un int
en mémoire pour chaque boucle (et avant que vous ayez attribué votre pile entière avec des ints...). Notez que l'utilisation de ce int
est nécessaire et vous pouvez réutiliser la même variable.
comme souligné par Marco , le seuil actuel est plus dans le compilateur que dans la spécification de langue réelle ou l'exécution. Une fois que c'est recodé, vous pourriez en place avec quelques itérations. si vous utilisez par exemple Ideone , qui par défaut utilise l'ancien compilateur, vous pouvez obtenir plus de 1200 for
boucles facilement.
pour les boucles sont un indicateur de mauvaise conception. J'espère que cette question est purement hypothétique.
il y a une limite pour tous les C# compilés JUSQU'à MSIL. MSIL ne peut prendre en charge que 65535 variables locales. Si vos boucles for
sont comme celles que vous avez montrées dans l'exemple, chacune nécessite une variable.
il est possible que votre compilateur affecte des objets sur le tas pour agir comme stockage de variables locales, contournant cette limite. Cependant, je ne suis pas sûr que ce genre de résultats étranges viendrait de cela. Il peut y avoir des questions qui surgissent avec la réflexion ce qui rend une telle approche illégale.
entre 800 et 900 pour les boucles for(;;)
vides.
reflète L'approche de Marco13, sauf les boucles for(;;)
essayées:
for (;;) // 0
for (;;) // 1
for (;;) // 2
// ...
for (;;) // n_max
{
// empty body
}
il a fonctionné pour 800 emboîtés for(;;)
, mais il a donné la même erreur que Marco13 rencontré en essayant 900 boucles.
lors de sa compilation, le for(;;)
semble bloquer le thread sans maxer le CPU; superficiellement, il semble agir comme un Thread.Sleep()
.