In un int?[]
che si è procurato di avere valori originali, volevo trovare l'indice di null, che sarà solo un indice singolo.
Ho eseguito il drill su Array.IndexOf(T[] array, T value)
.NET e, dopo tutti i contratti e i controlli dell'indice, si riduce a questo metodo:
internal virtual int IndexOf(T[] array, T value, int startIndex, int count){
int endIndex = startIndex + count;
for (int i = startIndex; i < endIndex; i++)
if (Equals(array[i], value)) return i;
return -1;
}
Ho tre diverse istanze che tentano un ciclo di base con array[i] == null
, Equals(array[i], null)
e usando Array.IndexOf(null)
. Mi rendo conto che le zecche e il tempo di cronometro sono relativi a ciò che accade sulla macchina in quel momento e alla macchina in generale. Ma questo è il codice e i benchmark:
class Program
{
static void Main(string[] args)
{
int?[] jankedArray;
int missingElement = GenRandomizedArrayWithExtraEmptyElement(10000, out jankedArray);
var sw = new Stopwatch();
List<long> DotNetTicks = new List<long>();
List<long> LikeDotNetTicks = new List<long>();
List<long> BasicLoopTicks = new List<long>();
IArrayAnalyzer arrayAnalyzer;
for (var i = 0; i < 100000; i++)
{
arrayAnalyzer = new AnalyzerLikeDotNet();
sw.Restart(); arrayAnalyzer.GetMissingElement(jankedArray); sw.Stop();
LikeDotNetTicks.Add(sw.ElapsedTicks);
arrayAnalyzer = new AnalyzerBasic();
sw.Restart(); arrayAnalyzer.GetMissingElement(jankedArray); sw.Stop();
BasicLoopTicks.Add(sw.ElapsedTicks);
arrayAnalyzer = new AnalyzerUsingDotNet();
sw.Restart(); arrayAnalyzer.GetMissingElement(jankedArray); sw.Stop();
DotNetTicks.Add(sw.ElapsedTicks);
}
Console.WriteLine("LikeDotNet / DotNet = " + LikeDotNetTicks.Average() / DotNetTicks.Average());
Console.WriteLine("Basic / DotNet = " + BasicLoopTicks.Average() / DotNetTicks.Average());
Console.WriteLine("");
Console.WriteLine("Press the Any key to continue");
Console.ReadKey();
}
public static int GenRandomizedArrayWithExtraEmptyElement(int valueCount, out int?[] incompleteArray)
{
incompleteArray = new int?[valueCount + 1];
Random random = new Random();
int randomMissingIndex = random.Next(0, valueCount);
var valueArray = new List<int>();
for (var i = 1; i <= valueCount; i++) valueArray.Add(i);
var arrayElementAt = 0;
while (valueArray.Count > 0)
{
if (arrayElementAt != randomMissingIndex)
{
var randomElement = random.Next(0, valueArray.Count);
var valueAtRandom = valueArray.ElementAt(randomElement);
valueArray.RemoveAt(randomElement);
incompleteArray[arrayElementAt] = valueAtRandom;
}
arrayElementAt++;
}
return randomMissingIndex;
}
}
public interface IArrayAnalyzer
{
int GetMissingElement(int?[] incompleteArray);
}
public class AnalyzerUsingDotNet : IArrayAnalyzer
{
public int GetMissingElement(int?[] incompleteArray)
{
return Array.IndexOf(incompleteArray, null);
}
}
public class AnalyzerLikeDotNet : IArrayAnalyzer
{
public int GetMissingElement(int?[] array)
{
for (int i = 0; i < array.Length; i++)
if (Equals(array[i], null)) return i;
return -1;
}
}
public class AnalyzerBasic : IArrayAnalyzer
{
public int GetMissingElement(int?[] array)
{
for (int i = 0; i < array.Length; i++)
if (array[i] == null) return i;
return -1;
}
}
- Output:
- LikeDotNet / DotNet = 81.3577324867023
- Base / DotNet = 3.29459064916075
Cosa mi manca tra AnalyzerLikeDotNet e AnalyzerUsingDotNet che rende così diverso il tempo di esecuzione?