Mai mult ca sigur stiti ce face metoda ToLower( cand vreti sa transformati un string, pentru a avea toate caracterele mici este nevoie sa apelam la aceasta metoda).
Daca ne uitam peste definitie, o sa observam ca exista 3 variante
Rezultatul pe care l-am obtinut este destul de interesant:
Daca ne uitam peste definitie, o sa observam ca exista 3 variante
- ToLower()
- ToLowerInvariant()
- ToLower(CultureInfo cultureInfo)
string uppertText = "Salut. Ce MAI fACI?";
CultureInfo cultureInfo = CultureInfo.CurrentCulture;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for( int i=0; i<100000000; i++)
{
string lowerText = upperText.ToLower();
//string lowerText = upperText.ToLowerInvariant();
//string lowerText = upperText.ToLower(cultureInfo);
}
stopwatch.Stop();
Console.WriteLine("Elapsed type: {0}",stopwatch.Elapsed);
Rezultatul pe care l-am obtinut este destul de interesant:
- ToLower() - 10.51 s
- ToLowerInvariant() - 17.32 s
- ToLower(CultureInfo cultureInfo) - 8.52 s
public static string ToLowerTest(this string value)
{
char[] output = value.ToCharArray();
for (int i = 0; i < output.Length; i++)
{
if (output[i] >= 'A' &&
output[i] <= 'Z')
{
output[i] = (char)(output[i] + 32);
}
}
return new string(output);
}
Dacă lucrezi doar cu caractere ASCII e ok, ToLowerTest va face ce trebuie, dar nu mi se pare un mare spor de viteză. În momentul în care apelezi metoda ToLowerTest, timpul cel mai mare va fi ocupat de cele două alocări de memorie - copierea în 'output' și apoi alocarea pentru stringul returnat - la care se adaugă copierea în noul string (dacă nu cumva copierea de pe urmă este realizată cu move semantics).
ReplyDeleteDacă vrei un spor mai mare de performanță, you go native (lași un milion de stringuri la îndemîna unei funcții în C(++) care să facă treaba pentru tine). Asta, desigur, dacă vrei spor real de performanță :)
O mare problema de performanta in operatiuni .NET cu stringuri este ca suporta toate caracterele Unicode. Principalul motiv pentru care se foloseste ToLower, cel putin din experienta mea, este comparare de stringuri. Dar deja exista niste metode specifice de comparare de stringuri care folosesc enumul StringComparison. StringComparison are si niste valori ca Ordinal si OrdinalIgnoreCase care sint folosite atunci cind nu mai conteaza Unicodeul, ci se presupune ca fiecare caracter are un byte. De obicei, viteza cu Ordinal e de 3-4 ori mai mare decit operatiunile normale.
ReplyDeleteIar la faza cu C++ ca sa mearga repede este bullshit. Nu toate operatiunile .NET sint managed code, mai ales cele de baza, iar daca vrei sa fii mai catolic decit papa poti oricind sa iti faci propriile metode unsafe si sa lucrezi cu pointeri. Daca nu ma crezi, baga niste reflection pe metodele .Net. (da, stiu, reflectionul nu exista in C++, dar nu e greu de invatat >:))
Iar sa utilizezi un dll de C++ in .NET implica(in afara codului) si niste costuri de transmisie ....
ReplyDeleteDiferenta intre ToLower() simplu si ToLower(CultureInfo) e mica si usor de explicat, deoarece ToLower() obtine de fiecare date CurrentCulture si CurrentThread, pe cand ToLower(CultureInfo) va primi referinta la CultureInfo "gata obtinuta" de fiecare data.
ReplyDeleteToLowerInvariant nu face chiar acelasi lucru, ci va folosi InvariantCulture, evident (chiar daca culture curenta e en-US, nu e garanta ca va face exact acelasi lucru).
In spate, toate apeleaza TextInfo.InternalChangeCaseString care nu m-as mira sa apeleze cod nativ gen tolower din wctype.h... (nu are rost sa reinventeze roata)
Cand e vorba de comparare de stringuri, se recomanda oricum ToUpperInvariant in loc de ToLowerInvariant. (ToUpper e un pic mai optimizat si mai "safe" in unele cazuri obscure).