Skriptování v .NETu 8 (Závěrečné porovnání)

Dost bylo jednotlivých skriptovacích jazyků. Myslím, že jsem vybral zástupce nejčastějších a nejzajímavějších jazyků, které by se pro .NETové prostředí daly použít. Pojďme je nyní porovnat a shrnout jejich klady a zápory.

Pro úplnost uvádím seznam skriptovacích jazyků s odkazy na jednotlivé díly seriálu, které jsme zatím prozkoumali:

  • DotScript (jazyky C# a VB)
  • IronPython
  • IronRuby
  • Lua
  • Boo
  • JScript .NET
  • PowerShell

Tyto jazyky by se daly rozdělit do třech skupin. Skupina jazyků, které jsou implementovány nad Dynamic Language Runtime – IronPython, IronRuby.

Skupina jazyků, které jsou pomocí CodeDomProvideru nebo jinak překládány přímo do CLI, a dále se reflexí pracuje s vytvořenými třídami a voláním funkcí nebo metod. – DotScript, Boo, JScript .NET.

Poslední zbývající jazyky jsou: Lua (používá plně managed knihovnu LuaInterface) a PowerShell, který není třeba představovat.

Vyhodnocení

Skriptovací jazyky jsem porovnával v sedmi kategoriích, které si popíšeme. Základem vyhodnocení je následující tabulka, ve které jsou zaznamenané časy jednotlivých měření (v milisekundách). Každý test se opakoval milionkrát. U některých měření jsem musel změnšít počet opakování z důvodu velké časové náročnosti (výsledný čas jsem samozřejmě vynásobil, aby bylo měření poměrově v pořádku).

  DotScript IronPython IronRuby Lua Boo JScript .NET PowerShell
Parsování / kompilace (první) 160 1600 1450 300 750 125 1300
Parsování / kompilace (opakovaná) 160 50 50 20 100 80 130
Float test 1753 18451 2045800 60884 2070 2310 3714700
Faktoriál test 2260 21981 2096220 18815 2534 4669 19126400
Zápis do skriptu 1860 4086 502 2059 598 641 1200
Čtení ze skriptu 1835 4092 443 1767 524 554 1100
Vytvoření instance 7644 14353 2928030 5267 3448 3075 4626000

Nyní si rozeberme jednotlivé kategorie a ke slovu přijdou slibované grafy. :)

Parsování / kompilace (první)

V tomto čase se hodně projevuje režie, která je z větší části dána načítáním potřebných assembly. 
Zde trvá nejdéle inicializace skriptovacích jazyků založených na Dynamic Language Runtime.

Parsování / Kompilace (první)

Parsování / kompilace (opakovaná)

Při opakované inicializaci skriptovacího engine jsou už všechny assembly nahrané, a tak čas vypovídá o zpracování zdrojových kódů.
V tomto testu zvítězil jazyk Lua, který je v tomto směru rychle zpracovatelný.

Parsovaní / kompilace (opakovaná)

Float test

Tento test měl změřit, jak rychle si skript dokáže poradit s výpočtem rovnice
sin2(30)+cos2(30), a výsledek (metody/funkce) vrátit hlavnímu programu. Čas udává milion opakování testu.
V tomto testu jsou nejlepší jazyky, které jsou přímo překládány do CIL.

Test zpracování desetinných čísel Osa Y je v logaritmickém měřítku.

 

Faktoriál test

Test spočíval ve výpočtu faktoriálu čísla 12 (tedy 12!) rekurzivním voláním funkce a vrácení výsledku (z metody/funkce) hlavnímu programu. Čas udává milion opakování testu.
V tomto testu byl o hodně horší PowerShell, ve kterém bylo opakované rekurzivní volání velmi pomalé. 

factorial  Osa Y je v logaritmickém měřítku.

Čtení hodnoty proměnné ze skriptu

Čtení hodnoty ze skriptu se používá tam, kde je třeba přečíst výsledek, který skript počítal. Jedná se o volání metody, která proměnnou z kontextu skriptovacího jazyka přečte a hodnotu vrátí do hlavního programu. Čas udává milion opakování testu.
Větší čas u jazyka IronPython je dán tím, že se četla členská proměnná testovací třídy namísto globální proměnné u jazyka IronPython.

Přečtení hodnoty ze skriptu

Zápis hodnoty proměnné do skriptu

Zápis proměnné z hlavního programu se používá zpravidla na začátku před samotným výpočtem. Většinou se jedná pouze o volání metody, která proměnnou v kontextu skriptovacího jazyka nastaví. Čas udává milion opakování testu.
Větší čas u jazyka IronPython je dán tím, že se zapisovala členská proměnná testovací třídy namísto globální proměnné u jazyka IronPython.

Nastavení hodnoty do skriptu

Vytvoření instance třídy ve skriptu

Úkolem tohoto testu bylo vrátit instanci třídy ze skriptu tak, aby se mohla v hlavním programu použít. Malou výjimkou zde byl jazyk Lua, který místo objektů používá systém tabulek, ve kterých jsou jak záznamy pro data (členské proměnné), tak pro funkce.

instance

Závěrečné hodnocení

Nyní si u jednotlivých jazyků shrneme klady a zápory podle výsledků a subjektivního názoru na syntaxi. Podrobnější informace k jednotlivým jazykům se můžete dočíst v předcházejících dílech seriálu.

Pokud bychom výpočty ze skriptovacího jazyka potřebovali volat opakovaně (např. při výpočtu animace, apod.), a hodně záleželo na rychlosti, doporučuji využít skriptovací jazyky, které svůj kód před použitím zkompilují do CLI tedy: DotScript, Boo nebo JScript.NET.

DotScript (C# a VB)

Knihovna DotScript je zaobalení CodeDomProvideru a umožňuje zpracovat jazyky C# a VB. Pokud skriptuje programátor, je velká výhoda právě použití těchto jazyků – programátor se nemusí učit nic nového. Z vyhodnocení testů vyplývá, že toto řešení je velmi rychlé. Avšak z testu čtení a zápisu proměnných vyplívá, že DotScript má okolo těchto operací větší režii.

IronPython, IronRuby

IronPython je jazyk, který vyniká svou přehledností i u velkých projektů. IronRuby je zase snadno naučitelný. Oba tyto jazyky jsou implementovány nad Dynamic Language Runtime, což je “podhoubí” pro libovolné skriptovací jazyky. V testech dopadl poměrně dobře IronPython – jeho rychlost by ve většině případů neměla ovlivnit aplikaci. U IronRuby se to říci nedá. Bohužel testy ukázaly pomalost např. při výpočtu faktoriálu.

Lua

Tento jednoduchý jazyk byl nejrychlejší ve zpracování zdrojového kódu skriptu. Ve vyhodnocování byl průměrný. Ovšem ve výsledku se jedná o velmi dobré řešení, které v mnoha úlohách splní svůj účel. 

Boo

Tento jazyk byl pro mne milým překvapením, protože jsem ho do té doby neznal. Je stejně přehledný jako Python (byl jím inspirován) a má velkou rychlost z důvodu kompilace do CLI před použitím. Ze subjektivního poměru rychlost/syntaxe ho považuji za vítěze testů.

JScript .NET

Tento jazyk představuje etalon v rychlosti skriptování. V článku o JScript .NET jsem ukázal použití CodeDomProvideru, což je asi nejoptimálnější způsob, jak v .NETu skriptovat, pokud můžeme použít reflexi k operacím mezi skriptem a hlavním programem. Syntaxe JScript .NET je také výhodná, pokud by měl psát skripty někdo se znalostmi JavaScriptu – např. webový vývojář.

PowerShell

Tento jazyk jsem zařadil z čisté zvědavosti, protože mě zajímala jeho integrace do .NETových programů. Bohužel mě trochu zklamala pomalost, ale ta může být za určitých podmínek vykoupena známostí PowerShellu a dostupnou dokumentací.

Závěr

Doufám, že vám tato moje malá exkurze do světa skriptovacích jazyků trochu pomohla s určením toho, který z nich je pro vás v daném případě nejvhodnější.

Pro úplný závěr seriálu chybí ještě jeden test – nějaký z praxe, na kterém by se ukázaly naplno klady a zápory daného jazyka. Proto poslední článek tohoto seriálu bude o praktickém použití. Přiložím také zdrojové kódy, ve kterých bude vidět integrace jednotlivých skriptovacích jazyků.

PS: Můžete se těšit na želvičku! (Vykreslování L-System fraktálů) :)

Posted 07 října 09 08:45 by topas | 86 Comments   
Filed under ,
Skriptování v .NETu 7 (PowerShell)

PowerShell určitě není třeba představovat – jedná se o shell a skriptovací jazyk z díly Microsoftu. Jeho syntaxe je poměrně intuitivní a přehledná. Hlavní výhodu jeho použití jako skriptovacího jazyka vidím právě v jeho rozšíření a známosti nejenom v programátorských kruzích - i správcové sítí či administrátoři obecně by jej mohli znát. O PowerShellu toho bylo napsáno opravdu hodně. Pojďme se ale zabývat něčím, co moc popsáno není, a to je použití Powershellu jako skriptovacího jazyka.

Použití

Nyní si ukážeme, jak integrovat PowerShell jako skriptovací jazyk. Nejlepší bude, když do projektu přidáme referenci na System.Management.Automation.dll, kterou najdeme po instalaci PowerShellu v GAC. Potom stačí tento jednoduchý kód:

Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline p = rs.CreatePipeline(" \"World!\".Insert(0, \"Hello \")");
// spustit a vypsat vysledek
foreach(PSObject o in p.Invoke())
  Console.WriteLine(o.ToString());

Více informací v MSDN k Powershell Runspace.

Syntaxe PowerShellu

$found = false
$abc = 7, 2, 4, 5, 6
for ($i=1; $i -le 5; $i++)
{
  if ($abc[$i] -gt 5)
  {
     $found = true 
  }
}

Testování

Z důvodu pomalosti volání PowerShellu jsem místo milionu opakování zvolil pouze deset tisíc, a výsledek vynásobil 100x, aby byl zachován poměr rychlostí vůči ostatním jazykům.

Parsování / kompilace

první 1300 ms
další okolo 130 ms

Float test 3714700 ms
Faktorial test 19126400 ms
Zápis hodnoty do skriptu 1200 ms
Čtení hodnoty ze skriptu 1100 ms
Vytvoření instance 4626000 ms

 

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Závěr

PowerShell nám uzavřel tento miniseriál o skriptování. Myslím, že jako základ to stačí a každý si vybere jazyk, který je mu nejbližší. Aby se však lépe vybíralo, budou závěrečné 2 díly srovnávací.

PS: A budou i nějaké grafy. :)

Posted 06 října 09 09:22 by topas | 57 Comments   
Filed under ,
Skriptování v .NETu 6 (JScript .NET, CodeDomProvider)

Tento díl bude menším opakováním. První díl popisoval skriptování pomocí knihovny DotScript, která používá abstraktní třídu CodeDomProvider ke kompilaci do assembly, kterou bychom mohli dále využívat pomocí reflexe.

Knihovna DotScript, která CodeDomProvider zaobaluje, ale umí pouze jazyky C# a VB. Je to škoda, protože existuje implementace CodeDomProvier-u pro jazyk JScript .NET. Stejný postup, který popíše tento článek, můžeme aplikovat i pro jazyky Boo a F#, protože pro ně existuje implementace CodeDomProvider-u také.

JScript .NET

Jazyk JScript .NET, za jehož vývojem stojí firma Microsoft, bych označil jako dialekt jazyka Java Script. Jak už název napovídá, lze s ním přistupovat ke všem prvkům platformy .NET a výsledek přeložit do CLI.
Jako úvod do tohoto jazyka bych doporučil článek Introducing JScript .NET na MSDN.

CodeDomProvider

Jedná se o abstraktní třídu a způsob, jak zkompilovat kód pro různé jazyky platformy .NET. Prakticky si ukážeme pouze JScript .NET, ale stačí pouze změnit jméno typu provideru, a tím kompilovat skripty v C#, VB, F#, Boo a určitě budou existovat další.

Jednoduchý kód, který vytvoří instanci třídy TestClass (k dalšímu použití třídy můžeme přestupovat přes reflexi a nebo interface, pokud jej máme k dispozici):

using System.CodeDom.Compiler;
...
// vytvorit provider
CodeDomProvider provider = (CodeDomProvider)Activator.CreateInstance("Microsoft.JScript", "Microsoft.JScript.JScriptCodeProvider").Unwrap();
// Parametry kompilace
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.IncludeDebugInformation = false;
cp.GenerateExecutable = false;
// Vlastni kompilace
CompilerResults cr = provider.CompileAssemblyFromFile(cp, "script.js");
// Z cr.Errors muzeme cist seznam syntaktickych chyb a varovani
Assembly assembly = cr.CompiledAssembly;
// Vytvorime objekt
object o = Activator.CreateInstance(assembly.GetType("TestClass"));

Syntaxe

var found = false;
var abc = [7, 2, 4, 5, 6];
for (i=0; i<5; i++)
{
    if (abc[ i ]>5)
        found = true;
}

Testování

Na závěr jenom rutinní testování tohoto řešení, které slibuje velkou rychlost z důvodu překladu do CLI před použitím.

Parsování / kompilace

první 100 – 150 ms
další okolo 80 ms

Float test 2310 ms
Faktorial test 4669 ms
Zápis hodnoty do skriptu 641 ms
Čtení hodnoty ze skriptu 554 ms
Vytvoření instance 3075 ms

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Závěr

Jako poslední skriptovací jazyk jsem vybral PowerShell, který je známý nejenom v programátorských kruzích. Ale o tom až v dalším dílu. :)

Posted 02 října 09 08:15 by topas | 2 Comments   
Filed under ,
Skriptování v .NETu 5 (Boo)

Tento díl seriálu Skriptování bude o nepříliš známém jazyce Boo, který je v aktivním vývoji (licencován MIT/BSD licencí). Jedná se o jazyk, kterým lze kompilovat zdrojové kódy přímo do mezikódu CLI, a tím pádem lze očekávat velkou rychlost. Samotný jazyk je velmi přehledný – vychází z jazyka Python a je silně typový, ačkoliv použití typů není povinné. Osobně se mi Boo libí a přijde mi rozhodně přehlednější než Visual Basic (možná kvůli tomu, že používám primárně C#).

Boo

Jazyk Boo rozhodně doporučuji k bližšímu prozkoumání. Má mnoho zajímavých vlastností a za zmínku rozhodně stojí snadná kompilace několika způsoby. Nás ovšem zajímá použití jako skriptovacího jazyka, které je velmi hezky řešeno. Zdrojový kód se zkompiluje a je vrácena vytvořená assembly, ve které je možné pomocí reflexe provádět všechny standardní operace.

Pokud se v kódu vyskytne syntaktická chyba, tak není assembly vytvořena a je vrácena kolekce chyb s popisem a přesným údajem o místě (řádek, sloupec). Považuji to za lepší (rychlejší) řešení než odchytávání výjimky jako v předchozích případech.

Syntaxe jazyka Boo

found as bool = false
abc = (7, 2, 4, 5, 6)
for i in range(4):
    if abc[ i ]>5:
      
found = true

Pokud se chcete s jazykem Boo rychle seznámit, doporučuji Boo reference quick card

Testování

Jak jsem se již v úvodu zmiňoval, dá se předpokládat poměrně vysoká rychlost zpracování skriptů. O přesném výsledku si ale budeme moci udělat obrázek až v posledním dílu seriálu.

Parsování / kompilace

první 500 – 1000 ms
další okolo 100 ms

Float test 2070 ms
Faktorial test 2534 ms
Zápis hodnoty do skriptu 598 ms
Čtení hodnoty ze skriptu 524 ms
Vytvoření instance 3448 ms

 

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Závěr

V dalším dílu se podíváme na JScript.NET a prakticky si ukážeme, jak se pracuje s třídou CodeDomProvider ke kompilaci javascriptových kódů.

Posted 02 října 09 04:50 by topas | 0 Comments   
Filed under ,
Skriptování v .NETu 4 (Lua)

Podívejme se nyní na skriptovací procedurální jazyk Lua, který je známý v herním průmyslu. Využívá ho např. World of Warcraft, Neverwinter Nights, Escape from Monkey Island, a další. O hrách lze obecně prohlásit, že se jedná o programy, které jsou hodně náročné na výkon počítače a je nutné, aby v nich vše běželo co nejrychleji. To se dá říci i o skriptovacím engine. Výchozím předpokladem pro jazyk Lua je tedy rychlost a jednoduchost.

LuaInterface

V minulém dílu jsme opustili skriptování nad Dynamic Language Runtime a nyní se podíváme na knihovnu LuaInterface (Pro DLR existuje projekt Nua). Jedná se o velmi jednoduchý koncept. Vytvoří se jeden objekt typu LuaInterface.Lua, pomocí kterého máme přístup k vykonávání kódu. Čtení a zápis proměnných jsou řešeny velmi elegantně přes indexer.

Zpracování syntaktických chyb je v LuaInterface poněkud nešikovné. Chyba se oznámí vyvoláním výjimky, ve které se chyba popisuje pouze textem. Určení chybného řádku by znameno parsování textu, ve kterém je číslo řádku uvedeno. 

Detaily použití a celého konceptu můžete najít v paperu LuaInterface: Scripting the .NET CLR with Lua.

Syntaxte jazyka Lua

found = false
abc = {7, 2, 4, 5, 6}
for i=0,4,1 do
   if abc[ i ] > 5 then
     found = true
   end
end

Testování

Předběžné výsledky testů ukazují, že se jedná o rychlejší jazyk nebo implementaci, než IronPython nebo IronRuby.

 

Parsování / kompilace

první 200 – 400 ms
další 3 – 30 ms

Float test 60884 ms
Faktorial test 18815 ms
Zápis hodnoty do skriptu 2059 ms
Čtení hodnoty ze skriptu 1767 ms
Vytvoření instance 5267 ms *

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.
* V případě jazyka Lua se o instance objektů v pravém slova smyslu nejedná. Lua používá tabulky, které mohou obsahovat jak položky datové, tak položky funkcí.

Poznámka: Testování probíhá na počítači s procesorem Intel Core Duo 2 (P8400) @ 2.26 GHz, 4 GB RAM, operační systém Windows Vista Ultimate.

Závěr

Příště se podíváme na nepříliš známý jazyk Boo a podrobíme ho stejným testům.

Posted 01 října 09 09:46 by topas | 1 Comments   
Filed under ,
Skriptování v .NETu 3 (IronRuby)

Ve třetím dílu se podíváme blíž na skriptovací jazyk Ruby a jeho implementaci v .NETovém prostředí - IronRuby (pod licencí Ms-PL). Jedná se o plně objektový jazyk, který je vyvíjen od roku 1993 – je tedy velmi mladý. Jeho přednostmi jsou především přehlednost a snadnost na naučení a díky tomu se v poslední době těší velké oblibě především pro webový vývoj pomocí frameworku Ruby on Rails.

Dynamic Language Runtime

Stejně jako IronPython je IronRuby implementován nad Dynamic Language Runtime, což je knihovna pro snadnější zpracování skriptovacích jazyků pod .NETem. K dispozici je abstraktní rozhraní, a tak lze jednoduše vytvořit aplikaci, ve které se mohou skriptovací jazyky přepínat. V současné době můžeme přes tuto knihovnu najít poměrně velké množství jazyků, např.:

Dynamic Language Runtime velmi usnadňuje tvorbu interpretů vlastních programovacích jazyků a lze najít mnoho článků, které se tímto tématem zabývají. Doporučuji tento přehled na blogu Benjamina Nitschke.

Myslím, že to by mohlo být k Dynamic Language Runtime vše – další skriptovací jazyky budou používat jiné technologie.

Syntaxe Ruby

Pro úplnost uvedu také syntaxi jazyka Ruby na stejném kódu jako vždy.

found = false
abc = [7, 2, 4, 5, 6]
for i in 1..5
   if (abc[ i ]>5)
      found = true
   end

end

Hezký návod syntaxe jazyka Ruby můžete najít na příkladech s jazykem C#

Testování

Testování implementace IronRuby přes DLR bylo poněkud komplikovanější než IronPython v předchozím díle. Při testování vycházely velké časy, takže jsem nakonec počet opakování jednotlivých testů zvolil o řád nižší – tedy 100000. Aby byly hodnoty porovnatelné, změřený čas jsem nakonec vynásobil 10x.

Parsování / kompilace

první 1100 – 2000 ms
další 30 – 100 ms

Float test 2045800 ms
Faktorial test 2096220 ms
Zápis hodnoty do skriptu 502 ms
Čtení hodnoty ze skriptu 443 ms / 1058360 ms *
Vytvoření instance 2928030 ms

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

* První (menší) číslo je čtení globální proměnné. Druhé (větší) číslo je čtení členské proměnné, vytvořené instance třídy v Ruby.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Poznámka: Testování probíhá na počítači s procesorem Intel Core Duo 2 (P8400) @ 2.26 GHz, 4 GB RAM, operační systém Windows Vista Ultimate.

Závěr

V příštím dílu se podíváme na jazyk Lua, který je známý použitím v herním průmyslu pro svou jednoduchost a rychlost.

Posted 30 září 09 07:56 by topas | 3 Comments   
Filed under ,
Skriptování v .NETu 2 (IronPython)

Druhý díl seriálu o skriptování v .NETu bude o jazyku Python a jeho implementaci pro .NET, a to IronPython (vyvíjeno přímo Microsoftem). Python je poměrně mladý programovací jazyk a jeho předností je přehlednost. Samotná syntaxe nutí programátora psát čitelně, protože jednotlivé bloky kódu se řeší odsazením.

Celkově považuji Python za velmi povedený jazyk, ve kterém se, díky jeho přehlednosti, dají psát malé programy i velké projekty.

Syntaxe jazyka Python

Syntaxi budu demonstrovat na stejném kódu jako v předchozím dílu seriálu.


found = False
abc = array([7,2,4,5,6])
for i in range(0,4):
if abc[ i ]; > 5:
found = True

IronPython

Jak jsem již zmínil v úvodu, IronPython je implementace jazyka firmou Microsoft. Je k dispozici pod licencí Ms-PL. Je také součástí Dynamic Language Runtime, což je knihovna, která poskytuje jednotné rozhraní nad více skriptovacími jazyky.

Pokud chcete použít IronPython jako skriptovací jazyk pro .NET, doporučuji přečíst těchto pár článků, ve kterých je popsáno vše podstatné.

Místo a popis případných syntaktických chyb je popsáno ve výjimce (Microsoft.Scripting.SyntaxErrorException), která vznikce při spuštění skriptu. 

Python a jeho interpretace není známa jako rychlá záležitost, což se ukázalo i v následujícím testování. Stejně jako v předchozím (prvním) dílu seriálu podotýkám, že testování bude mít smysl až v posledním srovnávacím dílu.

Testování

Parsování / kompilace první 1200 – 2000 ms
další 30 – 100 ms
Float test 18451 ms
Faktorial test 21981 ms
Zápis hodnoty do skriptu 4086 ms
Čtení hodnoty ze skriptu 4092 ms
Vytvoření instance 14353 ms

 

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Poznámka: Testování probíhá na počítači s procesorem Intel Core Duo 2 (P8400) @ 2.26 GHz, 4 GB RAM, operační systém Windows Vista Ultimate.

Závěr

Ačkoliv jsem původně tento jazyk neplánoval zahrnout do testování, tak se příště podíváme na jazyk IronRuby, který slibuje rychlý vývoj a snadnost na naučení. 

Posted 29 září 09 10:43 by topas | 27 Comments   
Filed under ,
Skriptování v .NETu 1 (DotScript)

Na úvod malého seriálu, který se bude věnovat skriptování a jeho implementaci v .NETu, bych si dovolil jenom motivační definici převzatou z wikipedie.

Typicky skript těží z výhody, že se nemusí překládat, a často tvoří rozšiřitelnou (parametrickou) část nějakého softwarového projektu, která se může měnit, aniž by bylo potřeba pokaždé rekompilovat hlavní spustitelný soubor. Tak skripty najdeme u her, složitějších softwarových řešení nebo jako hlavní součást dynamických internetových stránek a podobně.

U každého skriptovacího jazyka budu pro úplnost uvádět ukázku syntaxe (bude prezentována na podmínce, cyklu a deklaraci proměnných), popíši skriptovací engine, možnost vracení syntaktických chyb a na závěr uvedu výsledky testování rychlosti řešení a jeho výhody a nevýhody. V posledním díle tohoto seriálu porovnám jednotlivé skriptovací jazyky a jejich použití v .NETových aplikacích, aby bylo možné se pro nějaký rozhodnout.

Jazyky C# a VB

Programovací jazyky C# (C sharp) a VB (Visual Basic), si myslím, není třeba představovat – jedná se o hlavní programovací jazyky platformy .NET. Z toho plyne hlavní výhoda použití těchto jazyků jako skriptovacích – programátor se nemusí učit nic nového.

Příklad syntaxe C#


bool found = false;
int [] abc = {7,2,4,5,6}
for (int i=0; i<5; i++)
{
  if (i>5)
    found = true;
}

Příklad syntaxe VB


Dim found As Boolean = False
Dim abc As Integer() = New Integer(){7,2,4,5,6} 
For i = 1 To 10 Step 1
  If i>5 Then 
    found = true
  End If
Next i

 

DotScript

Pro zpracování skriptů napsaných v jazyce C# nebo VB můžeme použít např. knihovnu DotScript, která je hostována na Codeplexu.

Knihovna interně využívá CSharpCodeProvider a VBScriptProvider ke kompilaci zdrojových kódů do dočasné assembly. Z ní se potom klasickým způsobem přes Activator vytvoří instance požadované třídy. Dále nic nebrání volání metod (používá se opět reflexe) nebo k vytvořené instanci třídy přistupovat přímo, např. přes interface.

Vracení syntaktických chyb při kompilaci hodnotím velmi dobře – je použita kolekce tříd CompilerError, ve kterých lze najít informace o sloupci a řádku chyby a k dispozici je i lokalizovaná hláška s jejím popisem.

Testování

Vzhledem k tomu, že při kompilaci dochází k překladu do .NETového mezikódu, dalo by se čekat, že skriptování tímto způsobem bude poměrně rychlé. Na závěr proto uvádím tabulku s průměrnými rychlostmi jednotlivých testovacích operací. Svůj pravý význam bude mít tabulka až v posledním dílu seriálu, protože bude možné porovnat jednotlivé skriptovací jazyky.

Parsování / kompilace 120 ms
Float test 1753 ms
Faktorial test 2260 ms
Zápis hodnoty do skriptu 1860 ms
Čtení hodnoty ze skriptu 1835 ms
Vytvoření instance 7644 ms

Parsování / kompilace – doba, kterou potřebuje skriptovací engine k inicializaci (parsování nebo kompilaci zdrojových kódů).

Float test – doba potřebná k vypočítání jednoho milionu rovnic sin(30)*sin(30)+cos(30)*cos(30).

Faktorial test – doba potřebná k výpočtu faktoriálu čísla 12 (12!) rekurzivně. Prověřuje rychlost interního volání funkce, vyhodnocování podmínek a počítání s celými čísly. Test je volán milionkrát.

Zápis hodnoty do skriptu – milionkrát zapíše hodnotu z hlavního programu do skriptu.

Čtení hodnoty ze skriptu – milionkrát přečte hodnotu ze skriptu.

Vytvoření instance – vytvoří milion instancí objektu ze skriptu.

Poznámka: Testování probíhá na počítači s procesorem Intel Core Duo 2 (P8400), 4 GB RAM, operační systém Windows Vista Ultimate.

Závěr

V dalších dílech se můžete těšit na jazyky IronPython, Lua, PowerShell a Boo.

Posted 26 září 09 08:39 by topas | 68 Comments   
Filed under ,
Vista gadget - Mezera

Jak jsem psal v článku Vista – záhadné probouzení v noci je tomu chvilka, co jsem se stal uživatelem Windows Vista. Přemýšlel jsem, jakým způsobem tento přechod “oslavit” a jediná věc, která ve Vistách oproti XP na první pohled praští do očí, je postranní panel (sidebar). Nechci tu psát žádný sáhodlouhý návod o tom, jak gadgety tvořit – o tom bylo napsáno už dost. Dovolím si pouze pár poznámek z vývoje:

  • Pokud chcete napsat jednoduchý gadget, který jenom zobrazuje “hello world!”, je to opravdu otázka chvilky. U ostatních případů to není tak jednoduché. Pro zobrazení se používá HTML a funkcionalitu lze napsat v jazyce javascript – jedná se o speciální webovou stránku.
  • Práce s uživatelským nastavením je velmi jednoduchá a dostačující. Dialog pro nastavení je také tvořen HTML a o ukládání/načítání se starají připravené javascriptové funkce.
  • Trochu problém je průhlednost. Nelze použít transparentní barvu pozadí, transparentní obrázek ani nic podobného, protože potom je např. u písma vidět růžový okraj a celkově to nevypadá dobře. Je nutné použít metodu popsanou např. zde – jde o to, že se musí do definovaného obrázku na pozadí transparentní obrázek vložit pomocí metody addImageObject, která průhlednost zachovává. Pro text je dobré použít podobnou metodu addTextObject.
  • Je dobré si z gallery.live.com stáhnout nějakou inspiraci, která se po instalaci rozbalí do adresáře %USERPROFILE%\AppData\Local\Microsoft\Windows Sidebar\

Tolik asi k vývoji gadgetů. :)

Ten, na kterém jsem “oslavil” používání Windows Vista se jmenuje Mezera a má velmi jednoduché použití – zkrátka přidá mezeru mezi ostatní gadgety, aby se daly např. zarovnat na střed nebo dolů. Nic víc, nic míň. Volba barvy oddělovací čáry je pouze třešnička na dortu, aby v nastavení vůbec něco bylo. :)

Českou i anglickou verzi si můžete stáhnout z mých stránek.

Posted 22 září 09 04:01 by topas | 3 Comments   
Filed under
Lokalizované texty tlačítek v .NETu

Nevím jestli jsem v .NET Frameworku někde něco přehlédl, ale nikde jsem nenarazil na způsob, jakým se dostat k standardním textům tlačítek, které mění text na základě vlastní lokalizace Windows. Samozřejmě, že v .NET aplikacích je v celku jednoduchý způsob, jak na lokalizace… ale proč zbytečně řešit nějaké překlady, když by se jednalo například o jednoduchý dialog?

Trochu jsem po tom pátral a zjistil, že způsob, jak dostat texty tlačítek existuje. Texty jsou uloženy ve knihovně user32.dll, která je uložena v systémovém adresáři Windows. Stačí tedy tuto knihovnu otevřít (LoadLibrary), načíst text (LoadString) a uvolnit knihovnu (FreeLibrary) – všechno jsou, bohužel, unmanaged funkce systému. 

Texty tlačítek mají následující konstanty (myslím, že názvy jsou vypovídající):

private const uint OK_ID = 800;
private const uint CANCEL_ID = 801;
private const uint ABORT_ID = 802;
private const uint RETRY_ID = 803;
private const uint IGNORE_ID = 804;
private const uint YES_ID = 805;
private const uint NO_ID = 806;
private const uint CLOSE_ID = 807;
private const uint HELP_ID = 808;
private const uint TRYAGAIN_ID = 809;
private const uint CONTINUE_ID = 810;

Jednoduchá metoda, která dělá postup uvedený v úvodu vypadá takto:

/// <summary>
/// Vrati systemovou hlasku
/// </summary>
/// <param name="id_text">ID textu</param>
/// <returns>Vraci lokalizovany text</returns>
public static string GetText(uint id_text)
{
IntPtr user32 = LoadLibrary(Environment.SystemDirectory + "\\User32.dll");
StringBuilder sb = new StringBuilder(256);
LoadString(user32, id_text, sb, sb.Capacity);
FreeLibrary(user32);
return sb.ToString();
}


[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int LoadString(IntPtr hInstance, uint uID,
StringBuilder lpBuffer, int nBufferMax);

[DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string lpFileName);
 
Obalení kódu do nějaké třídy, případně vylepšení stávajícího tlačítka (System.Windows.Forms.Button) a automatické nastavení textu na základě vlastnosti DialogResult už nechám na vás.
 
PS: Fakt to v tom .NET Frameworku nikde není? :)

Zjištění informací z PIF souboru

Soubor PIF (Program Information File) je soubor – zástupce, který vzniknul za účelem spouštění DOSových programů. Na rozdíl od současného formátu zástupců (LNK) obsahuje informace o přidělené paměti, velikosti okna, nastavení písma apod.

Jedná se o binární formát, ve kterém jsou data uvedeny podle následující struktury: http://www.smsoft.ru/en/pifdoc.htm. Struktura je zde popsána velmi hezky a tak nebyl problém vytvořit velmi jednoduchou třídu, která zástupce PIF čte:

/// <summary>
/// Cteni PIF souboru
/// http://www.smsoft.ru/en/pifdoc.htm
/// </summary>
public class PIFReader
{
private string m_TargetFilename = null;
private string m_WindowTitle = null;
private string m_WorkingDir = null;
private string m_Parameters = null;


/// <summary>
/// Cilovy soubor
/// </summary>
public string TargetFilename
{
get
{
return m_TargetFilename;
}
}

/// <summary>
/// Titulek okna
/// </summary>
public string WindowTitle
{
get
{
return m_WindowTitle;
}
}

/// <summary>
/// Pracovni adresar
/// </summary>
public string WorkingDir
{
get
{
return m_WorkingDir;
}
}

/// <summary>
/// Parametry spusteni
/// </summary>
public string Parameters
{
get
{
return m_Parameters;
}
}


/// <summary>
/// Konstruktor
/// </summary>
public PIFReader()
{
}

/// <summary>
/// Konstruktor
/// </summary>
/// <param name="filename">Nazev souboru k otevreni</param>
public PIFReader(string filename)
{
Read(filename);
}

/// <summary>
/// Konstruktor
/// </summary>
/// <param name="filename">Nazev souboru</param>
/// <param name="encoding">Kodovani</param>
public PIFReader(string filename, Encoding encoding)
{
Read(filename, encoding);
}

/// <summary>
/// Precte soubor s vychozim kodovanim
/// </summary>
/// <param name="filename"></param>
public void Read(string filename)
{
Read(filename, Encoding.Default);
}

/// <summary>
/// Precte obsah PIF souboru
/// </summary>
/// <param name="filename">soubor</param>
public void Read(string filename, Encoding encoding)
{
FileStream fs = new FileStream(filename, FileMode.Open);
byte[] bBuffer = new byte[128];

fs.Seek(0x0002, SeekOrigin.Begin);
fs.Read(bBuffer, 0, 30);
m_WindowTitle = BufferToString(bBuffer, encoding);

fs.Seek(0x0065, SeekOrigin.Begin);
fs.Read(bBuffer, 0, 64);
m_WorkingDir = BufferToString(bBuffer, encoding);

fs.Seek(0x0024, SeekOrigin.Begin);
fs.Read(bBuffer, 0, 63);
m_TargetFilename = BufferToString(bBuffer, encoding);

fs.Seek(0x00A5, SeekOrigin.Begin);
fs.Read(bBuffer, 0, 64);
m_Parameters = BufferToString(bBuffer, encoding);

fs.Close();
}

/// <summary>
/// Konvertuje buffer do stringu
/// </summary>
/// <param name="buffer">data</param>
/// <param name="encoding">kodovani</param>
/// <returns></returns>
private string BufferToString(byte [] buffer, Encoding encoding)
{
string tmp = encoding.GetString(buffer).Trim();
int end = tmp.IndexOf('\0');
return tmp.Substring(0, end);
}

}

Pro zástupce vytvořené u nás v ČR doporučuji použít znakovou sadu 852 (Latin2) je dost pravděpodobné, že znaky v PIF souboru budou právě v tomto kódování.

Ačkoliv je formát zástupců PIF opravdu historická záležitost, doufám, že se to i v dnešní době bude někomu hodit. :)

Je to IČO?

Pro ušetření práce ostatním zveřejňuji kousek svého kódu (jednu metodu), která zjišťuje, jestli je IČO správné nebo ne. IČO má 8 číslic (starší čísla, která mají menší počet cifer se doplňují zleva nulami), kde poslední číslice je kontrolní. Celý algoritmus je popsán zde, ale lze ho jednoduše vyčíst kódu:

/// <summary>
/// Kontroluje správnost IČO
/// http://blog.vyvojar.cz/topas/
/// </summary>
/// <param name="ico">Identifikační číslo organizace</param>
/// <returns>true, pokud je to číslo validní</returns>
public bool IsICO(string ico)
{
if (ico == null)
throw new ArgumentException("Parameter ico cannot be null.");

ico = ico.Trim();
System.Text.RegularExpressions.Regex reg =
new System.Text.RegularExpressions.Regex(@"\d{8}");
if (reg.IsMatch(ico))
{
int checknum = ico[ico.Length - 1]-48;
int sum = 0;
int result;

for (int index = ico.Length - 2, multiplier=2; index>=0 ; index--,
multiplier++)
{
int num = ico[index] - 48;
sum += num * multiplier;
}

result = 11 - (sum % 11);
if (result >= 10)
result -= 10;

return checknum == result;
}
return false;
}

Nechť slouží. ;)

Posted 24 srpna 09 07:09 by topas | 32 Comments   
Filed under ,
Vista - záhadné probouzení v noci

Pořídil jsem si nový notebook a pomalu se stávám kamarádem s Vistou (ano, pár měsíců před vydáním Windows 7). Když je celý počítač výkonnější, tak ta náročnost Vist není ani znát. :) Nicméně… vraťme se zpátky k tématu článku.

Jak jsem objevoval nové vlastnosti a dokonalosti nového stroje, několikrát se mi stalo, že jsem se ráno probudil a notebook už na mě čekal také probuzený (z hibernace). Nekladl jsem tomu extra pozornost, ale když už se to stalo po několikáté, tak jsem po tom začal pátrat.

Nakonec se podle EventLogu ukázalo, že se notebook probouzí přesně ve 3:00 ráno. A to se čirou náhodou shoduje s automatickou instalací aktualizací.

Vysvětlení je jednoduché:

"If your computer is in one of the power-saving states (Sleep or Hibernate) during a scheduled update, and if your computer is plugged in to a power source, Windows will wake your computer long enough to install new updates."

Stačí tedy automatické instalace aktualizací vypnout. Dalo by se tedy říct, že probouzení není chyba, ale vlastnost. :)

Posted 13 srpna 09 09:18 by topas | 79 Comments   
Filed under
.NET a Zip komprese

Po zkoumání různých knihoven pro Zip kompresi jsem se rozhodl sepsat nějaký souhrn, který by pomohl někomu dalšímu ve správném výběru. Zaměřuji se na knihovny, které jsou k dispozici zdarma a jsou k dispozici se zdrojovými kódy. Komerční řešení nechme stranou.

Jaký vlastně máme výběr? Podařilo se mi najít 4 knihovny nebo způsoby, jak vytvořit Zip soubor. V úvodu jsem se zapomněl zmínit, že se zajímám o tvorbu Zip souboru nikoliv o DeflateStream, GZipStream a jim podobné kompresní udělátka. 

Vlastnosti knihoven uvádí následující tabulka:

Knihovna SharpZipLib DotNetZip ZipStorer ZipPackage ZipStorer 1.01
Adresa Icsharpcode CodePlex CodePlex MSDN CodePlex
Licence GPL Ms-PL Ms-PL součást Frameworku Ms-PL
Minimální Framework .NET 1.1 .NET 2.0 .NET 2.0 .NET 3.0 .NET 1.1
Compact Framework Ano Ano Ano Ne Ano
Velikost knihovny 185 kB 417 kB, redukovaná verze 164 kB 0 kB (žádná externí assembly) 0 kB (součást Frameworku) 0 kB (žádná externí assembly)
Poslední vydaná verze 8.11. 2008 28.8. 2009 10.3. 2010 - 14.6. 2009
Aktivní vývoj Ne Ano Ano - Ano

Poznámky a postřehy

SharpZipLib

  • Výborná knihovna podporující Zip, GZip, Tar a BZ2 kompresi
  • Licence obsahuje dodatek k GPL, ve kterém se umožňuje použití knihovny v programu jakékoli licence (i pro komerční použití), pokud je knihovna k programu referencována jako samostatná assembly.
  • Není aktivně vyvíjena
  • Upravená verze pro Silverlight: http://slsharpziplib.codeplex.com/

DotNetZip

  • Velmi snadné použití
  • Aktivní vývoj (po nahlášení chyby byla po pár dnech uvolněna opravená verze)

ZipStorer

  • Velmi snadné použití
  • Pro přidání do projektu – žádná externí assembly navíc

ZipPackage

  • Přímo součástí .NET Framework 3.0 a vyšší
  • Složitější způsob komprimace a dekomprimace
  • Vytváří uvnitř Zip souboru [Content_Types].xml, ve kterém jsou uloženy metadata k souborům (to může být problém např. při rozbalování pomocí jiného programu)

ZipStorer 1.01

  • Starší verze knihovny ZipStorer
  • Nekomprimuje data, jenom využívá struktury Zip souborů
  • Velmi jednoduchá – možnost použít v Silverlightu

Závěr

Osobně se mi velmi zalíbila knihovna DotNetZip, protože se velmi snadno používá a je v aktivním vývoji. Má také licenci, která umožňuje použití v komerčním software.

A co vy? Máte nějakou svou oblíbenou knihovnu a nebo nějaký tip?

Upraveno 7.4. 2010: Aktualizace tabulky s novými verzemi knihoven. 

Posted 04 srpna 09 10:00 by topas | 8 Comments   
Filed under
.NET Remoting a NOD32

Pokud vám aplikace psaná v .NET Frameworku 2.0 využívající .NET Remoting zničehonic začne padat a chyba je v modulu imon.dll, pravděpodobně se jedná o až moc starostlivý antivirový program NOD32. První spojení se serverovou částí většinou projde, ale při dalším pokusu už aplikace spadne. Řešení existuje v podobě hotfixu, který není zabudován do žádného service packu, ale je k dispozici zvlášť.

Problém je popsán na microsoftí Knowledge-base: http://support.microsoft.com/kb/923028

A samotný hotfix je zde: http://code.msdn.microsoft.com/KB923028/Release/ProjectReleases.aspx?ReleaseId=773

Vyvojar.cz na prodej!