Dlaczego czas wykonania fragmentu kodu w C# nie jest powtarzalny?

0

Witam serdecznie.

Zgłębiając tajniki .NET chciałem sobie sprawdzić która metoda konwersji ze string do integer jest szybsza. Int.Parse() czy Convert.ToInt32();
Wyniki jakie otrzymuje za każdym razem różnią się od siebie i zastanawiam się dlaczego. Bardzo proszę o wyjaśnienie.

Kod programu:

using System;

namespace Konsola
{
	class Program
	{
		
		public static void Main(string[] args)
		{
			int count = 0;
			Random rand = new Random();
			string[] str = new string[30000];
			foreach (string element in str) {
				str[count] = rand.Next(1000,32000).ToString();
				count++;
			}
			Console.WriteLine(obliczaj_Convert(str));
			Console.WriteLine(obliczaj_Parse(str));
			Console.ReadKey();
		}
		
	
	public static string obliczaj_Convert(string[] str)
		{
			string strwynik;
			System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
			watch.Reset();
			watch.Start();

			for (int i = 0; i < str.Length; i++) {
				Convert.ToInt32(str[i]);
			}
			watch.Stop();
			strwynik = "Convert\nczas wykonania w ms: " + watch.ElapsedMilliseconds + "\n" + "czas w taktach procka: " + watch.ElapsedTicks + "\n";
			return strwynik;
		}
	public static string obliczaj_Parse(string[] str)
		{
			string strwynik;
			System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
			watch.Reset();
			watch.Start();

			for (int i = 0; i < str.Length; i++) {
				Int32.Parse(str[i]);
			}
			watch.Stop();
			strwynik = "Parse\nczas wykonania w ms: " + watch.ElapsedMilliseconds + "\n" + "czas w taktach procka: " + watch.ElapsedTicks + "\n";
			return strwynik;
		}
	}
}
1

Jedyna różnica jest taka że Convert.ToInt32 sprawdza czy wartość jest nullowa jeśli tak to zwraca zero. Dlatego Convert powinien być troszkę wolniejszy ale różnica będzie prawie nie zauważalna. A żeby otrzymać bardziej reprezentatywne wyniki zapętl jeszcze tą cześć i uśrednij wyniki.

Console.WriteLine(obliczaj_Convert(str));
Console.WriteLine(obliczaj_Parse(str));
public static int Parse(string s)
{
    return System.Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
internal static unsafe int ParseInt32(string s, NumberStyles style, NumberFormatInfo info)
{
    byte* stackBuffer = stackalloc byte[1 * 0x72];
    NumberBuffer number = new NumberBuffer(stackBuffer);
    int num = 0;
    StringToNumber(s, style, ref number, info, false);
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
    {
        if (!HexNumberToInt32(ref number, ref num))
        {
            throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
        }
        return num;
    }
    if (!NumberToInt32(ref number, ref num))
    {
        throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
    }
    return num;
}
public static int ToInt32(string value)
{
    if (value == null)
    {
        return 0;
    }
    return int.Parse(value, CultureInfo.CurrentCulture);
}

Źródło: http://stackoverflow.com/questions/199470/whats-the-main-difference-between-int-parse-and-convert-toint32

http://referencesource.microsoft.com/#mscorlib/system/convert.cs,069d595792a157df
http://referencesource.microsoft.com/#mscorlib/system/int32.cs,a438016f815a35c3
http://referencesource.microsoft.com/#mscorlib/system/number.cs,fc92e899c667fab0

0

Dziękuję za odpowiedź. Już jestem mądrzejszy. Jednak chodziło mi o to, że kolejne wywołania tego programu zwracają czasy różniące się od siebie nawet o 2 ms. Po pięciu wywołaniach tego programu metoda Parse była szybsza trzy razy a metoda Convert dała lepszy czas dwa razy. Za każdym razem kiedy uruchamiam ten program otrzymuję inne wyniki. Zastanawiam się dlaczego. Spodziewałem się różnic ale znacznie mniejszych. Czy tak się dzieje przez programy działające w tle?

3

Jednak chodziło mi o to, że kolejne wywołania tego programu zwracają czasy różniące się od siebie nawet o 2 ms.

Nawet? Czy w Twoim programie strata 2ms jest aż tak bardzo znacząca, żeby się tym przejmować?

Po pięciu wywołaniach tego programu metoda Parse była szybsza trzy razy a metoda Convert dała lepszy czas dwa razy.

Jeżeli już testujesz jakiś algorytm, to wykonuj pomiary na tysiącach wywołań, bo tylko wtedy pomiary i wyniki będą w miarę sensowne;

Za każdym razem kiedy uruchamiam ten program otrzymuję inne wyniki.

I najprawdopodobniej za każdym razem będziesz dostawał inne wyniki - to normalne; Dlatego aby uzyskać dokładny wynik pomiarów, testy przeprowadza się na dużej liczbie powtórzeń i z dużą dokładnością;

Spodziewałem się różnic ale znacznie mniejszych. Czy tak się dzieje przez programy działające w tle?

Całkiem możliwe, dlatego testy warto przeprowadzać na całkiem odciążonej maszynie, aby inne procesy nie zabierały czasu procesora; Druga sprawa to testowanie algorytmów na mocno obciążonej maszynie - będzie wiadomo jaka jest ich efektywność w bardzo złych warunkach, przy czym różnice czasów mogą być dużo, dużo większe.

0

przed mierzeniem czasu należy też funkcje odpalić parokrotnie żeby JIT compiler zrobił swoje - nazywa się to zazwyczaj "rozgrzewką"
dopiero po tych kilku uruchomieniach funkcji czasy (w idealnych warunkach) stają się powtarzalne

0

Dziękuję bardzo za rzeczowe odpowiedzi.

Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1