Archive for the ‘C#’ Category

.NET teljesítményhangolási tapasztalatok 4.

Thursday, February 5th, 2009

Óvakodj az enumtól, mert lassú lészen az - áll a .NET bibliában.

Ártatlan kis jószágnak néz ki ez az enum, mégis sokszor láttam már, hogy miatta lassul be egy rendszer. Mi a lassú rajta? Minden. A Parsolás pl. De ez még érthető is. De hogy a ToString() is tetű, az már kevésbé. Sajnos azonban reflectiont használ ezekhez a műveletekhez, ami köztudottan lassú.
Szerencsére elég könnyű segíteni a baján. Ha Parsolni kell, azaz egy string alapján kell egy enum értéket megszülni, akkor ezt egyszerűen meg lehet oldani egy Dictionary-vel, ami string kulcsokkal és az konkrét enum értékekkel van feltöltve.
Most a másik oldalt mutatom meg, a turbó ToString()-et.
Egyszerű demó enumunk:


public enum TradeDirection
{
    Short,
    Long
}

Ebből tehát ha van egy példányunk amin ToString()-et hívunk, az lassú lesz. Hozzunk létre egy Dictionary-t, ami segít az enum-string asszociációban.


private static Dictionary<TradeDirection, string> tradeDirectionNames = new Dictionary<TradeDirection, string>();

Ezt kellene felölteni értékekkel. A C# generikus dolgaival szépen meg lehet ezt általánosan is fogalmazni, így mindenféle enumra működni fog:


tradeDirectionNames.FillEnumCache();

public static void FillEnumCache<T>(this Dictionary<T, string> enumNames)
{
    foreach (T enumValue in Enum.GetValues(typeof(T)))
    {
        enumNames.Add(enumValue, enumValue.ToString());
    }
}

Mivel extension methodként írtam meg olyan, mintha a Dictionary tudná ezt a funkciót, a T típusparamétert meg kitalálja a compiler, így nem kell kiírjam a teljes alakot:


tradeDirectionNames<TradeDirection>.FillEnumCache();

Hogy jogos-e erre az extension method az objektumorientált szempontból erősen vitatható, de nekem így kézre esett.

A generizálhatóság viszont szenzációs. Ezért imádom a C#-ot.

Miután a fenti megoldással gyorsítottam a rendszeren kiderült (profilerrel, mi mással), hogy egy összetett típusban ami két enumból állt lassú volt a GetHashCode implementációm, ami így nézett ki:


public override int GetHashCode()
{
    return dir.GetHashCode() + zone.GetHashCode();
}

A dir és a zone egy-egy enum.

A gyorsításhoz így írtam át:


public override int GetHashCode()
{
    return (int)dir << 4 + (int)zone;
}

Ez nem csak gyorsabb, de jobban is szór, mint az előző.

Debugolás a .NET fw. forrása segítségével

Thursday, December 11th, 2008

Kaptam egy igen nehezen megközelíthető problémát, amelyben a fókusz a TAB-ra átlépett egyes controlokat. Nem egy triviális TabStop=false probléma volt.
VS 2005-ös projektekről van szó, átkonvertáltam őket 2008-ra, hogy tudjam a fw. forráskódját is debugolni. Az _NT_SYMBOL_PATH= nekem be van állítva a gépen a publikus os szimbólumokra (elsősorban ahhoz amikor WinDbgozok), emiatt nem tudtam a vsből .net fw.-öt debugolni, mert előbb lehúzza a stripped szimbólumokat, a teljeshez már hozzá se nyúl. Ezért egy bat-ból indítom a vs-t, előtte kiütve az eredeti _NT_SYMBOL_PATH-t.
Így már ment a fw. forrás debug, de mivel a clr az ngenelt optimalizált kódot töltötte be, ezért nagyon sok típus belseje nem látszik normálisan. Erre megoldás itt található. Le lehet tiltani, hogy a CLR az ngenelt kódot töltse be, így már rendesen lehet debugolni.
Lehetne, ha nem lenne elcsúszva némelyik forráskód a pdb-ben található sorszámoktól. Ilyenkor van az, hogy teljesen más sorokon lépkedünk végig, mint amit a source ablakban látunk, pl. kommenteken lépked végig a debugger.
A megoldás erre egyszerűbb volt, mint gondoltam volna: próbaképpen kitöröltem 3 sort pl. a Control.cs elejéből, így visszaállt a szinkron.
Maga az alapprobléma egyébként abból adódott, hogy egy kompozit Third Party Contol explicit letiltotta
a TAB-olást, a ControlStyle-ból kivéve a Selectable flaget.

Scott Hanselman - The Weekly Source Code

Friday, July 18th, 2008

A legutóbbi msdn magazinban nézelődve láttam, hogy hivatkoznak Scott gyerek sorozatára. Mivel az ő blogjára már pont nem voltam feliratkozva (régebben a SharpReader miatt fenn voltam), nem értesültem róla.
No, ő sok kódot olvas, elvégre a MS azért vette fel vagy 2 éve, hogy takarítsa ki a fw. kódját, mielőtt kiadják az egészet.
A “The Weekly Source Code” sorozatában érdekes kódokat boncolgat, érdemes végigmenni rajtuk, aki szereti más kódját olvasni. Steve McConnell (gondolom nem kell bemutatni) szerint az egyik legjobb kódírás tanulási mód ez, mások kódját olvasni.

Például a 27. részben a reflection helyett mutat egy sokkal gyorsabb kódgenerálós dinamikus property elérést, vagy IIS7 (nem tévedés!) hosztolását saját processzben.

Amint lesz időm-erőm nézem a többi részt is, ha találok valami érdekeset, leírom.

C++ linker elszállás elleni gyógyír

Saturday, July 12th, 2008

A VS 2008-ra áttérés nekem nagy csalódás volt, mert a C++ fordítás során gyakran elszállt a linker, csúnya belső hibákkal. Az inkrementális linkelés kikapcsolása időlegesen megoldotta a dolgot, de azért egy fatális hiba a linkerben az nem szép dolog, és az Edit and Continue-s debugoláshoz meg kell ez a fajta linkelés.

Szerencsére már elég régóta van rá gyógyír, csak én most vettem észre. Eddig úgy tűnik segít, de majd a jövő héten jobban kiderül, amikor intenzíven használom.

Mi az a Dynamic Data?

Wednesday, May 28th, 2008

5 perces kis videó a témáról.

Valami olyasmi cucc ez, amivel rendkívül gyorsan össze lehet rakni CRUD jellegű adatkezelő website-okat, de teljesen testreszabható módon, template alapon, nem sima kódgenerálással. Érdekes megoldás, de nem tudom mennyire lesz majd használható.

LINQ Framework Design Guidelines

Thursday, April 10th, 2008

Az olyanoknak, mint én, akik csak ugatják a témát hasznos ez.

Lejtőn a VB, emelkedő ágon a C#

Tuesday, February 26th, 2008

A jó öreg C++ meg még mindig keresettebb, mint az előző kettő. A JAVA-ról csönd. :) (Az a legkeresettebb, legalábbis ezen adatok alapján.)

Forrás.

Az SQL Server is felfelé megy, azt én vettem már hozzá a képhez, bár gyanúsan együtt fut a Javaval, lehet, hogy nem stimmel valami.

Állások száma

LINQ vs. SQL teljesítmény

Tuesday, February 12th, 2008

Az előző cikkemmel csak az volt a célom, hogy megmutassam, hogyan lehet megírni ugyanazt a lekérdezést kétféle módon, a teljesítményüket nem is vizsgátam, mivel érzésre egyik se volt túl lassú.

Laci kommentjében a teljesítmény kérdésre hívta fel a figyelmem, hát megnéztem, mi itt a helyzet. Nos, megúszta a LINQ, pedig nem akartam neki reklámot csinálni. Pontosan ugyanolyan teljesítményű lett a két megoldás, ami nem csoda, hisz pontosan ugyanaz az SQL végrehajtási tervet eredményezik! Egyetlen különbség, hogy a sorszámozást LINQ esetén csak procedurálisan tudtam megcsinálni, így a LINQ sql-es kódjában az nem szerepel, de ennek költsége nem is jelent meg a tiszta SQL megoldás végrehajtási tervében, annyira kicsi.

A lényeg tehát, hogy a LINQ nem feltétlenül lassú, sőt, teljesen egyenértékű lehet a hagyományos SQL-es megoldással. De miért is lenne más? Hisz egyszerűen arról van szó, hogy másképp írom le ugyanazt a specifikációt, az egész hatékonysága azon múlik, mennyire okos a LINQ to SQL sqlgenerátora. A jelek szerint egyszerűbb lekérdezésekre tökéletes.

Aki nem hiszi amit írok, nézze meg az alábbi képet (rákattintva nagyban).

LINQ vs SQL teljesítmény

LINQ vs. SQL

Monday, February 11th, 2008

Melyik a szimpatikusabb?


select bucid, score, countMatchedEcid, ROW_NUMBER()
OVER(ORDER BY score DESC) AS 'rank'
from (
select
b.ucid as bucid,
a.ucid as aucid,
sum(w.weight) as score,
count(*) as countMatchedEcid
from EcidNameValueSummary a,
genecidparts b,
weights w
where a.id=b.id
and a.value=b.value
and a.ucid!=b.ucid
and w.id=a.id
and w.allowed=1
and w.limit>=a.countEcids
and a.ucid=@ucid
group by b.ucid, a.ucid
) as hits

var matchQuery = from t in
    (from a in c.EcidNameValueSummaries
    join b in c.genecidparts
    on a.id equals b.id
    join w in c.Weights
    on a.id equals w.id
    where w.allowed == 1
    && w.limit >= a.countEcids
    && a.value == b.value
    && a.ucid != b.ucid
    && a.ucid == ucid
    select new
    {
        bucid = b.ucid,
        aucid = a.ucid,
        score = w.weight1
    })
group t by t.bucid into g
orderby g.Sum(e => e.score) descending
select new RankEntity
{
    Ucid = g.Key,
    Score = g.Sum(e => e.score) ?? 0,
    CountMatched = g.Count(),
    Rank = 0
};

BindingListCollection<RankEntity> ranks =
new BindingListCollection<RankEntity>();
int i = 1;
//It would be cool to do this with linq, but...
foreach (RankEntity e in matchQuery)
{
    e.Rank = i++;
    ranks.Add(e);
}
return ranks;

És emellett, a ROW_NUMBER-t át tudná nekem valaki fordítani LINQ-ra?

LINQ hatékony szűrés

Tuesday, January 29th, 2008

Mi van, ha egy LINQ kifejezésben olyan szűrést szeretnénk végrehajtani, amit a LINQ2SQL réteg nem tud okosan végrehajtani, mert pl. TSQL függvényt kellene használnunk a where feltételben?
Ha nem ügyeskedünk, átjön a 100 millió sor az adatelérő rétegbe, aztán szűr a LINQ maga. Szép is lenne.

No, az okosság az ilyen esetekre az, hogy lehet használni TSQL függvényeket a LINQ where feltételben. Ettől még nem lesz index seek, de legalább a szerver szűr.

A linkelt példát kipróbáltam, tényleg a szerver szűr.

AdwentureWorks-szel:


AWDataContext dc = new AWDataContext();
dc.Log = Console.Out;

var q = from o in dc.PurchaseOrderHeaders
        where dc.WeekOfYear(o.OrderDate) == 23
        select o;

foreach (var item in q)
{
    Console.WriteLine(item.OrderDate);
}

ALTER FUNCTION WeekOfYear(@Date DateTime)
RETURNS Int
AS
BEGIN
RETURN (CAST(DATEPART(ww, @Date) AS INT))
END

Az SQL, ami bemegy a szerverhez:


SELECT [t0].[PurchaseOrderID], [t0].[RevisionNumber], [t0].[Status],
[t0].[EmployeeID], [t0].[VendorID], [t0].[ShipMethodID], [t0].[OrderDate],
[t0].[ShipDate],
 [t0].[SubTotal], [t0].[TaxAmt], [t0].[Freight], [t0].[TotalDue],
[t0].[ModifiedDate]
FROM [Purchasing].[PurchaseOrderHeader] AS [t0]
WHERE [dbo].[WeekOfYear]([t0].[OrderDate]) = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [23]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

MS C++ csapat póló felirat

Thursday, January 24th, 2008

“My compiler complied yours” :)

Nem árulok el nagy titkot, de a C#, VB, és C++ compilert C++-ban írják. Érdekes, hogy a UNIX-ok világában a C++ mostohagyerek, ami nem annyira a nyelv miatt van szerintem, hanem marhára sokféle C++ compiler implementáció létezik, amelyek apró, de fontos pontokon különböznek, így nem portolható a kód rendesen. Vagy laza a nyelvi szabvány, vagy kupi van a másik oldalon, ízlés kérdése.

Persze, az msnek könnyebb dolga van, nem kell több platformra dolgozni, más kérdés, hogy Windows alatt is van sokféle compiler, mégis működik közöttük a bináris együttműködés, köszönhető egy okos szabványnak, a COM-nak.
Igen, a COM nem halt ki, pedig azt hittük, ki fog. Sok ponton soha nem lesz a COM alternatívája a .NET. Miért? Tegyük fel, egy IE vagy Shell extensiont írok (most tényleg azt, az előbbit). Ha .NET-ben írom, akkor be kell töltődni az általam használt CLR-nek a target processzbe. Ok, eddig nincs nagy baj. De mi van, ha egy másik gyártó cucca meg más CLR verziót kér? Egy processzben csak egy CLR verzió lehet, aki először betöltődött, az nyert. Azért ez igen gázos dolog egy extension írónak, nem? Mi marad? ATL, C++.

Mostanában sokat tanulom a C++-t, kaptam a cégtől pár könyvet, és kicsit úgy érzem, kezdek nagykorúvá válni a programolásban. Még mindig nem értek hozzá, soha nem is fogok, de egyre több dolgot látok belőle, és napról-napra ledöbbenek, mennyi mindent nem tudok még. De jó érzés tanulni, mindig van mit.

Zárásul még két adalék. A C++ fordítót tényleg C++-ban írják, mindig a saját verzióval. Tehát, most írják a 2008 utáni C++ compilert, és annak a fordításához felhasználják a “félkész” C++ compilert. Meredek? :)

Ja, és a JScript.NET compilert C#-ban írták. :) Meg lehet nézni reflectorral, én nem találtam bennük C++/CLI maradványokat (modopt, stb.):
C:\Windows\Microsoft.NET\Framework\v2.0.50727\jsc.exe
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Microsoft.JScript.dll
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Microsoft.Vsa.dll

(A Sytem.Data pl. C++/CLI-ben készült, a program managere még a demókat is abban mutatta Redmondban).

DMF, SMO, LINQ példácska

Wednesday, January 23rd, 2008

Nézegettem az SQL 2008 könyvet, és az ottani példa alapján kedvem támadt kipróbálni a LINQ-t. Tetszik, nem tudom valódi appokban tényleg jó-e, de babrálni vele érdekes.


using System;
using System.Linq;
using Microsoft.SqlServer.Management.Dmf;

class Program
{
    static void Main(string[] args)
    {
        ConsoleColor origColor = Console.ForegroundColor;

        var fc = from f in PolicyStore.Facets
                 orderby f.DisplayName
                 select f;
        foreach (var fi in fc)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Facet {0}:", fi.DisplayName);
            Console.ForegroundColor = origColor;

            var props = from f in fi.FacetProperties
                        orderby f.Name
                        select f;
            int i = 0;
            foreach (var pi in props)
            {
                Console.Write(pi.Name);
                if (i++ > 0)
                    Console.Write(", ");
            }
            Console.WriteLine();
            Console.WriteLine("-----------------------------------");
        }
    }
}

Állítólag ez a DMF nagy durranás az adminoknak, tessék örülni neki és olvasni az ingyenes fejezetet.

Ingyenes LINQ könyv

Saturday, December 22nd, 2007

Aki ezek után azt mondja, hogy nem volt honnan tanulnia, nem hiszek neki. :)

Van itt még Ajax meg SilverLight könyv is.

LINQ Standard Query Operators doksi

Saturday, August 25th, 2007

Tanulgatom a bestiát, találtam hozzá egy jó leírást.

Az aljas XmlDataSource cachelés

Saturday, August 25th, 2007

Az egyik kedves ismerősöm keresett meg egy problémával, amiben véletlenszerűen gond volt egy DataBind-olt DropDownList-tel.

Kicsit körbejárva a problémát kiderült, hogy az XmlDataSource alapban cache-el keményen, ami statikus XML fájlok esetén nem lenne nagy gond, sőt, de dinamikus bemenetnél alattomos hibákat okozhat.
Az alábbi kódot párszor futtatva azonnal látszik a cache-elés okozta hiba, míg a xds.EnableCaching = false; sor hatására megszűnik.

[source:xhtml]
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


CssClass="middle" DataTextField="Azonosito"
DataValueField="Kod">



[/source]

[source:csharp]
using System;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
int a;
string[] gy = { “alma”, “korte” };

protected void Page_Load(object sender, EventArgs e)
{
XmlDataSource xds = new XmlDataSource();
//xds.EnableCaching = false;
this.Controls.Add(xds);
xds.ID = “d”;
a = new Random().Next(0, 2);

xds.Data = string.Format(
@”


“,
a, gy[a]);
xds.XPath = “Data/Row”;
ize.DataSourceID = “d”;
}

protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);

int b = int.Parse(ize.Items[0].Value);
if (b != a)
{
throw new InvalidOperationException(
string.Format(
“Baj van, elvárt érték a lista első elemében: {0}, tényleges: {1}”,
a, b));
}
}
}

[/source]

Microsoft Visual C++ 2005 Redistributable Package verziók

Tuesday, August 14th, 2007

Triviális, de sok felesleges időt el lehet vele tölteni, ezért leírom.
Ha egy Cpp programot szeretnénk futtatni egy szűz gépen, akkor (sok más mellett) szükséges feltelepíteni a fenti csomagot.
Csak arra kell ügyelni, hogy VS 2005 SP1-gyel fordított programhoz ez nem jó, hanem ezekhez a runtime lib SP1-es verziója dukál.

Melyik a gyorsabb?

Friday, August 10th, 2007

És miért?

[source:C#]
Stopwatch st = Stopwatch.StartNew();
char a = ‘1′;
char b = ‘a’;
for (int i = 0; i < 1000 * 1000 * 10; i++)
{
//string s1 = new string(new char[] { a, b });
//string s2 = a.ToString() + b.ToString();
}
st.Stop();

Console.WriteLine(st.Elapsed);
[/source]

Mit ír ki?

Friday, August 10th, 2007

Lefuttatni nem ér.

Console.WriteLine(new string(’1′, ‘b’));

A Linq to SQL várható sebessége a Beta2-ben

Friday, July 6th, 2007

Rico Mariani neve szerintem ismerős a .NET programozók körében, ő az MS egyik performace-hangoló embere.
Mivel kedvencem az optimalizálás, a blogjára mindig odafigyelek. Most a DLinket vette górcső alá, eddig 4 cikket írt róla (1 2 3 4).
A 4.-ben már a még ki nem adott Beta2-vel foglalkozik, amiben már majdnem olyan gyors a Linq mint a sima kézi sql, sőt, módosításoknál 4x gyorsabb. Miért? Olvassátok el a cikkeket. :)

Refactoring a C# fordító kódjában

Thursday, June 14th, 2007

Érdekes írás Eric Lipperttől, amelyen arról mesél hogyan takarítják a compiler kódját. Igen, mert olyan öreg, hogy már az is tele van retekkel.