Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

Bobrisuv blog

O .Netu, C#, F#, C++, Embeded databázích, prostě o všem o čem budu mít chuť psát.

Syndication

Štítky

Iterátory C# vs F#

Již jsem tu na blogu trochu kritizoval F# za nedostatečně optimální kód. Ted bych rád byl více konkrétní. Na pomoc jsem zavolal CLRProfiler. Napsal jsem dva “identické” programy. Nejdříve F# verzi:

    1 #light

    2 open System

    3 open System.IO

    4 

    5 let mutable fileCount = 0

    6 let mutable dirCount = 0

    7 

    8 let rec allFiles dir =

    9     seq {

   10         for file in Directory.GetFiles dir do

   11             fileCount <- fileCount + 1

   12             yield file

   13         for subdir in Directory.GetDirectories dir do

   14             dirCount <- dirCount + 1

   15             yield! (allFiles subdir)

   16         }

   17 

   18 for i in allFiles @"C:\Windows\System32\" do Console.WriteLine i

   19 printf "Files: %d Dirs: %d" fileCount dirCount

 

Krátké, výstižné, nedebugovatelné (ale to počítám, že snad s dalšími verzemi F# vyřeší) …

A pokračuje C# verze:

    1 using System;

    2 using System.IO;

    3 using System.Collections.Generic;

    4 

    5 namespace Test

    6 {

    7     class Program

    8     {

    9         static int fileCount = 0;

   10         static int dirCount = 0;

   11 

   12         static IEnumerable<string> allFiles(string aDir)

   13         {

   14             foreach (var file in Directory.GetFiles(aDir))

   15             {

   16                 fileCount++;

   17                 yield return file;

   18             }

   19             foreach (var subdir in Directory.GetDirectories(aDir))

   20             {

   21                 dirCount++;

   22                 foreach (var file in allFiles(subdir))

   23                 {

   24                     yield return file;

   25                 }

   26             }

   27         }

   28 

   29         static void Main(string[] aArgs)

   30         {

   31             foreach (var i in allFiles(@"C:\Windows\System32\")) Console.WriteLine(i);

   32             Console.WriteLine("Files: {0} Dirs: {1}", fileCount, dirCount);

   33         }

   34     }

   35 }

 

Delší (hlavně o závorky a chybějící “yield foreach”), ale taky myslím výstižné, bez problému debugovatelné.

Na mém počítači vypíše poslední WriteLine toto: (samozřejmě obě verze mají naprosto stejný výstup)

Files: 4924 Dirs: 243

No a teď výsledky z CLRProfileru: (zakroužkoval jsem objekty co jsou “navíc”, povšimněte si taky velikosti scrollbaru)

IterFSharpvsCSharp

Takže už víte co jsem myslel tím větším tlakem na GC. V tomto konkrétním případě s relativně dlouhými řetězci, to dělá o 30% hůře pro F# (112% v počtu instancí!).

PS: Vývojáři F#, ale mají u mne jedno malé plus za to, že #light režim bude výchozí nastavení. Začínám vidět výhody velmi kontroverzního Python like scope==indent :-) (Především vynucená disciplína alespoň nějakého vzhledu zdrojáků)

Zveřejněno Thursday, March 12, 2009 12:30 AM by bobris

Vedeno pod: ,

Upozornění na nové komentáře

Pokud chčeš dostávat upozornění emailem na změny u toho příspěvku,tak se zaregistruj zde.zde

Odebírat komentáře k tomuto příspěvku pomocí RSS

Komentář

# re: Iter&#225;tory C# vs F# @ Thursday, March 12, 2009 1:57 AM

Zdravim :-) zprava ktera vsechny urcite potesi je, ze v pristi verzi bude F# stejne jako C# prekladat iteratory do state machine misto puvodniho prekladu na volani metod ktere berou funkce jako parametr (to, ze ted to dela pomerne neefektivni veci je zrejme pri kouknuti do Reflectoru). To znamena ze spusteni iteratoru nebude znamenat zadne alokace objektu. Debugovani by melo fungovat pro sequence expressions take uplne normalne :-).

Hlavni zajimavost ale podle me je, ze sequence expressions jsou mnohem obecnejsi koncept, ktery je pouzitelny i pro jine veci - nicmene optimalizovat tenhle specificky pripad se rozhodne vyplati (podobny problem je u asynchronous workflows, ale tam je min vyrazny).

Dalsi zajimava vec je, ze F# bude mit optimalizovanou i kompilaci "yield!", takze ve vysledku by to cele mohlo byt i vyrazne rychlejsi nez C# (tim ze musite prochazet allFiles pomoci foreach vlastne vznikaji vnorene iteroatory, ktere cely pruchod zpomaluji - to v F# v pripdae tail-call nebude).

Takze, je na co se tesit :-).

Tomas Petricek

# re: Iter&#225;tory C# vs F# @ Thursday, March 12, 2009 8:37 AM

Tomas Petricek: Tak to jsou urcite skvele zpravy. Jo s tim yield! to bude taky zajimavy. Proto jsem taky zakrouskoval to d__0 v pripade C#, co tam prave vznika kvuli tomu foreach navic.

bobris

# re: Iterátory C# vs F# @ Thursday, March 12, 2009 5:29 PM

Abych byl presnejsi: ten objekt navic v C# musi vznikat a v F# tedy taky bude (neni to tailcall). Takze stejne pro optimalni iterovani stromu se stejne implementaci pres vlastni zasobnik nevyhneme.

Jen skoda se, ze ac ctu dost blogu o F#, tak se tam nic takoveho neobjevilo (si to tam kutej v tajnosti). No jsem zvedav jak to bude implementovano, jestli tedy seq a async budou nejak zadratovany do kompilatoru, nebo to bude umet nejak obecne optimalizovat na zaklade definice seq a async (to se mi nezda realne).

bobris

# re: Iterátory C# vs F# @ Thursday, March 12, 2009 11:37 PM

To je pravda - v tomhle pripade to tailcall (vramci sequence expression) neni, takze tam neco vznikat bude. Aspon clovek ale jasne vi na cem je, protoze se to chova vice-mene jako standardni F# kod.

Jinak tahle zmena je pomerne nova a asi zatim verjne moc zminena nebyla. Myslim, ze az bude hotova nejaka dalsi verze VS2010, tak tech informaci bude k dsipozici dost :-). Kompilace 'seq' bude podporovana primo kompilatorem - obecne by to v principu mozna slo, ale rozhodne to neni neco co se da udelat jen tak mimochodem pri opravovani bugu a stabilizovani F# aby mohlo byt ve VS...

Tomas Petricek

Vytvoření nového komentáře

(povinný) 
povinný 
(povinný) 
Opiš čísla, která vidíš na obrázku: