Skip to content

Instantly share code, notes, and snippets.

@rarous
Forked from renestein/Foreach.cs
Created April 16, 2012 07:46
Show Gist options
  • Save rarous/2396976 to your computer and use it in GitHub Desktop.
Save rarous/2396976 to your computer and use it in GitHub Desktop.
ForEach extension with micro optimization
public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (onNext == null)
{
throw new ArgumentNullException("onNext");
}
var array = source as TSource[];
if (array != null)
{
Array.ForEach(array, onNext);
return;
}
var list = source as List<TSource>;
if (list != null)
{
list.ForEach(onNext);
return;
}
foreach (TSource current in source)
{
onNext(current);
}
}
@renestein
Copy link

To je skutečně mikrooptimalizace a dokonce si nejsem jistý, jestli tohle bude rychlejší.
Chápu přetypovávání v metodě Count, kde nemusím počítat všechny prvky, tady už ale je ta motivace slabá.

@rarous
Copy link
Author

rarous commented Apr 16, 2012

Z měření před pár lety jsem dostával výsledky o několik řádů (~3) lepší. Při iteraci přes kolekce se stovkama až tisícema prvků. Měřeno v reálném kódu, ne jen v benchmarku. :)

@renestein
Copy link

Já jsem právě tohle nikdy nenasimuloval.

Navíc podívej na List a Array - pak by musel být cyklus for několikanásobně rychlejší než foreach. Nebyl ten problém někde jinde, nebo nemáš nějaký kód, na kterém by se dalo udělat repro? Zní to zajímavě.

public void ForEach(Action<T> action)
        {
            if (action == null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
            }
            for (int i = 0; i < this._size; i++)
            {
                action(this._items[i]);
            }
        }

public static void ForEach<T>(T[] array, Action<T> action)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            for (int i = 0; i < array.Length; i++)
            {
                action(array[i]);
            }
        }

@rarous
Copy link
Author

rarous commented Apr 16, 2012

Ano for je díky přímému přístupu na konkrétní index rychlejší než iterace Enumerátorem. Ta část s Listem by se dala zobecnit na IList<T> a proiterovat přes indexer. Já třeba ve svých projektech materializujeu kolekce do Array, takže většinou matchnu první průchod. :)

@rarous
Copy link
Author

rarous commented Apr 16, 2012

Navíc IEnumerable je ještě k tomu virtual call, což má taky svůj cost. Ale já měl specifickej případ, kdy jsem migroval spoustu dat z jednoho systému do novýho se zcala jinou strukturou a každé urychlení představovalo velké plus. Původní naivní implementace travala asi dva dny. Po různých optimalizacích (jak v návrhu tak microoptimalizace) to kleslo na pár hodin. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment