2010-08-02 2 views
5

Je suis en train d'accélérer les éléments suivants:Le moyen le plus efficace pour déterminer si une longueur de chaîne! = 0?

string s; //--> s is never null 

if (s.Length != 0) 
{ 
    <do something> 
} 

Le problème est, il semble que le .Length compte en fait les caractères de la chaîne, ce qui est beaucoup plus de travail que j'ai besoin. Quelqu'un a une idée sur la façon d'accélérer cela?

Ou existe-t-il un moyen de déterminer si s [0] existe, sans vérifier le reste de la chaîne?

+1

Le problème de perf vous faites face est très probablement résolu un autre! Avez-vous profilé et constaté que le goulot d'étranglement est vraiment là? –

+0

Par curiosité, quelle version du framework ciblez-vous? –

+0

** NOTE ** pour d'autres seraient-être-answerers: d'Eric a publié une réponse qui clarifie sa question (un peu) ci-dessous .... –

Répondre

5

L'accès à la propriété Length ne doit pas entraîner de comptage. Les chaînes .NET stockent un nombre à l'intérieur de l'objet.

Le SSCLI/Rotor source code contient un commentaire intéressant qui suggère que String.Length est (a) efficace et (b) la magie:

// Gets the length of this string 
// 
/// This is a EE implemented function so that the JIT can recognise is specially 
/// and eliminate checks on character fetchs in a loop like: 
/// for(int I = 0; I < str.Length; i++) str[i] 
/// The actually code generated for this will be one instruction and will be inlined. 
// 
public extern int Length { 
    [MethodImplAttribute(MethodImplOptions.InternalCall)] 
    get; 
} 
7

String.IsNullOrEmpty est la méthode préférée pour le contrôle des chaînes de longueur nulle ou zéro.

En interne, il utilisera Longueur. La propriété Length d'une chaîne ne doit pas être calculée à la volée.

Si vous êtes absolument certain que la chaîne ne sera jamais nul et vous avez une objection forte à String.IsNullOrEmpty, le code le plus efficace que je peux penser serait:

if(s.Length > 0) 
{ 
    // Do Something 
} 

Ou, peut-être même mieux:

if(s != "") 
{ 
    // Do Something 
} 
+0

assez juste, mais il est exagéré si la chaîne est connue pour ne pas être nulle. –

+0

Non seulement cela est exagéré, mais cela suggère que vous pensez que la variable * pourrait être nulle. –

+0

puis comparer avec 'String.Empty' – ankitjaininfo

3

est ici la fonction String.IsNullOrEmpty -

if (!String.IsNullOrEmpty(yourstring)) 
{ 
    // your code 
} 
+0

S'il vous plaît expliquer. – Hut8

+0

@bowenl, pourquoi avez-vous voté? – ankitjaininfo

+0

Parce que vous avez initialement posté quelque chose de différent qui n'a pas du tout été compilé. Je me suis rétracté maintenant que vous l'avez réparé pour correspondre à ce que quelqu'un d'autre posté avant vous. – Hut8

20

EDIT: Maintenant que vous avez fourni un peu plus de contexte:

  • Essayer de reproduire, je réussi à trouver un goulot d'étranglement dans string.Length du tout. La seule façon de le rendre plus rapide était de commenter à la fois le test et le corps du bloc if - ce qui n'est pas vraiment juste. Le simple fait de commenter la condition a ralenti les choses, c'est-à-dire que la copie inconditionnelle de la référence était plus lente que la vérification de la condition. Comme nous l'avons souligné, l'utilisation de la surcharge string.Split qui supprime les entrées vides pour vous est l'optimisation réelle du tueur.

  • Vous pouvez aller plus loin, en évitant de créer un nouveau tableau de char avec juste un espace à chaque fois. Vous allez toujours passer la même chose efficacement, alors pourquoi ne pas en profiter?

  • Les tableaux vides sont effectivement immuables. Vous pouvez optimiser le cas null/vide en retournant toujours la même chose.

Le code optimisé devient:

private static readonly char[] Delimiters = " ".ToCharArray(); 
private static readonly string[] EmptyArray = new string[0]; 

public static string[] SplitOnMultiSpaces(string text) 
{ 
    if (string.IsNullOrEmpty(text)) 
    { 
     return EmptyArray; 
    } 

    return text.Split(Delimiters, StringSplitOptions.RemoveEmptyEntries); 
} 

String.Length ne fait absolument pas compter les lettres dans la chaîne. La valeur est stockée sous la forme d'un champ - bien que je semble me souvenir que le bit supérieur de ce champ est utilisé pour se rappeler si tous les caractères sont ASCII (ou utilisés de toute façon) pour activer d'autres optimisations. Donc l'accès à la propriété peut avoir besoin de faire un bitmask, mais ce sera toujours O (1) et je m'attendrais à ce que le JIT l'insère aussi. (Il est mis en œuvre comme extern, mais nous espérons que n'affecterait pas le JIT dans ce cas -. Je pense qu'il est assez opération potentiellement avoir un soutien spécial commun)

Si vous savez déjà que la chaîne est non nulle, alors votre test existant de

if (s.Length != 0) 

est la meilleure façon de procéder si vous êtes à la recherche de performances brutes IMO. Personnellement, dans la plupart des cas j'écrire:

if (s != "") 

pour le rendre plus clair que nous ne sommes pas tellement intéressés par la longueur en tant que valeur si c'est la chaîne vide. Ce sera légèrement plus lent que le test de longueur, mais je crois que c'est plus clair. Comme toujours, j'irais chercher le code le plus clair jusqu'à ce que vous ayez des données de benchmark/profiling pour indiquer que c'est vraiment un goulot d'étranglement. Je sais que votre question concerne explicitement la recherche du test le plus efficace, mais je pensais que je le mentionnerais de toute façon. Avez-vous des preuves que ce est un goulot d'étranglement?

EDIT: Juste pour donner plus claires raisons de ma suggestion de pas à l'aide string.IsNullOrEmpty: un appel à cette méthode me suggère que l'appelant tente explicitement de traiter le cas où la variable est nulle, sinon ils n » Je l'ai mentionné. Si à ce point du code il compte comme un bogue si la variable est null, alors vous ne devriez pas essayer de le gérer comme un cas normal.

Dans ce cas, le chèque est en fait Lengthmieux d'une manière que le test de l'inégalité que je l'ai suggéré: il agit comme une affirmation implicite que la variable est non nulle. Si vous avez un bug et que est null, le test va lancer une exception et le bug sera détecté tôt. Si vous utilisez le test d'égalité, il traitera null comme étant différent de la chaîne vide, il ira donc dans le corps de votre instruction "if". Si vous utilisez string.IsNullOrEmpty, la valeur null sera considérée comme étant vide, de sorte qu'elle ne sera pas incluse dans le bloc.

+2

Je pense que la meilleure chose à ce sujet est la dernière ligne. – msarchet

+0

@msarchet: Il est regrettable que j'ai édité la réponse pendant que vous écriviez ce commentaire. Je suppose que vous voulez dire "Avez-vous des preuves que ceci * est * un goulot d'étranglement?" –

+0

oui, bien que ça s'applique encore – msarchet

0

Comme toujours avec performace: benchmark.
utilisant C# 3.5 ou avant, vous aurez envie de tester yourString.Length vs String.IsNullOrEmpty(yourString)

utilisant C# 4, effectuez les deux ci-dessus et ajoutez String.IsNullOrWhiteSpace(yourString)

Bien sûr, si vous savez que votre chaîne ne sera jamais vide, vous pouvez simplement essayer d'accéder à s[0] et gérer l'exception quand elle n'est pas là. Ce n'est pas normalement bonne pratique, mais il peut être plus proche de ce dont vous avez besoin (si s devrait toujours avoir une valeur non vide).

+0

'IsNullOrWhitespace' donnera cependant la mauvaise réponse, compte tenu des exigences de la question. –

0
 for (int i = 0; i < 100; i++) 
     { 
      System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); 
      string s = "dsfasdfsdafasd"; 

      timer.Start(); 
      if (s.Length > 0) 
      { 
      } 

      timer.Stop(); 
      System.Diagnostics.Debug.Write(String.Format("s.Length != 0 {0} ticks  ", timer.ElapsedTicks)); 

      timer.Reset(); 
      timer.Start(); 
      if (s == String.Empty) 
      { 
      } 

      timer.Stop(); 
      System.Diagnostics.Debug.WriteLine(String.Format("s== String.Empty {0} ticks", timer.ElapsedTicks)); 
     } 

Utilisation du chronomètre le s.length! = 0 prend moins les tiques puis s == String.Empty

après que je fixe le code

1

Sur la base de votre intention décrite dans votre réponse, pourquoi ne vous essayez simplement de ne pas utiliser cette option intégrée de Split sur:

s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries); 
0

utiliser juste String.Split (nouveau char [] { » « }, StringSplitOptions.RemoveEmptyEntries) et il fera tout pour vous.

Questions connexes