Dienstag, Juni 30, 2009

Improving .NET Application Performance

Ich habe lange überlegt, ob ich zu diesem Thema etwas schreibe, schließlich gibt es schon 100er von Blogs, die das Thema behandeln. Letztendlich habe ich mich doch dazu entschlossen, um einfach mal eine kleine Link-Sammlung zu dem Thema zu haben.

Den Post habe ich Anfang Mai angefangen, in der Zwischenzeit ist es schon fast Juli. Das Thema ist so umfangreich und jeden Tag kommt mehr zu dem Thema. Das letzte ist die Google Initiative “Let's make the web faster”. Das Thema passt zum Glück aber nicht ganz in diesen Teil rein. Eigentlich brauche ich zum Thema Web-App-Performance nichts mehr schreiben, Google hat alles zusammengetragen, was dazu gehört.

Bevor mit der Optimierung einer Anwendung begonnen wird, sollte man sich Ziele überlegen, die zuerreichen sind. Das soll einfach dazu dienen, dass man nicht das Projektbudget unnötig verbraucht. Außerdem sollte man unbedingt man die wesentlichen Kapitel im “Improving .NET Application Performance and Scalability”-Guide lesen, im Kapitel “Performance Best Practices at a Glance” geht es um das allgemeine Vorgehen zur Optimierung von Anwendungen. Mindestens ebenso Hilfreich ist der Pattern & Practice Guidance Explorer, hier sind viele Guides, Checklisten, …. Es ist sehr schwer Anwendungen zu optimieren, wenn das Anwendungsdesign nicht schon viele Prinzipien berücksichtigt hat. Dennoch lässt sich meistens einiges herausholen, allerdings sollte man vor jeder Optimierung MESSEN, anschließend die Optimierung durchführen und erneut Messen. Ach und natürlich die Unit-Tests erneut ausführen, um nicht ein fehlerhaftes Verhalten als Optimierung zu bezeichnen.

Ich hatte dievor einigen Wochen einige interessante Blog-Artikel zu Assemblies und Namespaces gelesen. Die meisten Verbinden mit Komponenten separate Assemblies, allerdings sollte jedem bewußtsein, dass mit zusätzlichen Assemblies die Ladezeiten steigen. (Sicherheitscheck, Auflösungen, …) Hier einer der Links: Advices on partitioning code through .NET assemblies - Patrick Smacchia

Im Blog von Rico Mariani kann man sehr viele nützliche Tips zu Performance finden, wer sich mit dem Thema beschäftigt, sollte sich das mal anschauen.

Loops

Jede Anwendung verfügt über Schleifen, zumindest kenne ich keine außer “Hello World” ohne Schleifen. In Abhängigkeit von der Anzahl und Häufigkeit der Schleifendruchläufe kann hier eine Optimierung der Anwendung auf die Sprünge helfen. In dem Blog Post von Patrick Smacchia “An easy and efficient way to improve net code performance” geht es auch genau um das Thema Loops und deren Einfluss auf die Performance. Für die Performance sind For-Schleifen günstiger, vor allem auf Array oder Listen. Foreach-Schleifen sind durch den IEnumerator/IEnumerable-Aufwand teurer. Hier muss bei jedem durchlauf IEnumerator.MoveNext und IEnumerator.Current aufgerufen werden.

Beim Refactoring von Schleifen sollte man zusätzliche darauf achten, dass nicht der Inhalt der Schleife in eine neue Methode gepackt wird, sondern ebenso die Schleife. Der Overhead, der beim Aurfuf einer Methode entsteht, multipliziert sich in einer Schleife. Mein folgendes Beispiel ist nicht sehr sinnvoll, aber verdeutlicht hoffentlich das Problem.

Ausgang:

   1: private void Loop()
   2: {
   3:     long sum = 1;
   4:     for (int i = 0; i < 10000; i++)
   5:     {
   6:         sum = i*2;
   7:         sum -= i;
   8:     }
   9:     Debug.WriteLine("Resut=" + sum);
  10: }

Ungünstige Optimierung:

   1: private void Loop()
   2: {
   3:     long sum = 1;
   4:     for (int i = 0; i < 10000; i++)
   5:     {
   6:         sum = GetSum(i);
   7:     }
   8:     Debug.WriteLine("Resut=" + sum);
   9: }
  10: private long GetSum(int i)
  11: {
  12:     long sum;
  13:     sum = i*2;
  14:     sum -= i;
  15:     return sum;
  16: }

Besser:

   1: private void Loop()
   2: {
   3:     long sum = 1;
   4:     sum = GetSum(sum);
   5:     Debug.WriteLine("Resut=" + sum);
   6: }
   7: private long GetSum(long sum)
   8: {
   9:     for (int i = 0; i < 10000; i++)
  10:     {
  11:         sum = i*2;
  12:         sum -= i;
  13:     }
  14:     return sum;
  15: }

Hier noch ein Post zur Laufzeit von verschiedenen Loops.

Casting

Dank Generics kann man das “Cast”en sein lassen. Ich casts sind nicht merkbar “teuer”, das Boxing von ValueTypes kostet einige CPU-Cycles. Allerdings kann das Boxing zu Laufzeitfehlern führen, die der Compiler mittels Generics bereits hätte prüfen könne. Ich verwende massig Generics, allerdings finde ich die Regel keine Generics als Public Properties oder Rückgaben zu verwenden, BLÖD.

Threading

… ist eins meiner Lieblingsthemen, leider kommt dieses Thema aber immer zu kurz und bei der Leistungsoptimierung von Anwendungen wird es oft verkannt. Durch den Einsatz von Threading kann man sich viele Probleme in einer Anwendung schaffen, zu dem kann nicht jede Anwendung mit Threading sinnvoll ausgestattet werden. Um die Probleme mit dem Threading zu reduzieren/vereinfachen, gibt es von Microsoft die Parallel Extensions. Es ist so einfach damit Anwendungen zu Parallelisieren und das auch  noch sehr performant. Die Parallel Extensions machen den Rechner nicht mit Threads zu, sondern verfügen über ein intelligentes Thread-Management bei dem eine Anzahl Arbeitsthreads, abhängig vom Prozessor, immer wieder mit den eigentlichen Aufgaben gefüllt wird. Einen Nachteil haben die Parallel Extensions allerdings, es gibt sie nur für Framework 4.0 und für das Framework 3.5 leider nur als CTP.

Eine andere Art Threading effektiv einzusetzen, ist System.Threading.ThreadPool.QueueUserWorkItem. Besonders effektiv ist der Einsatz in Client-Anwendungen, um das User-Interface während langen Operationen verfügbar zu belassen “Responsiveness”. Für Server-Anwendungen muss man etwas aufpassen bei dieser Variante, da der Standard .NET-ThreadPool auch für ASP.NET verwendet wird (evtl. auch WCF?), somit kann es passieren, dass der Server Anfragen ablehnt, weil zu viele Nutzertasks aktiv sind. Es gibt sogar ein schlimmeres Szenario, wenn der Server selber Web-Anfragen ausführt, dann kann es zu Deadlocks kommen. Also dabei etwas aufpassen.

Linq 2 Sql

Compiled Queries sind in Linq 2 Sql der weg um Abfragen zu beschleunigen, dabei wird bei der ersten Ausführung der Anfrage diese in .NET Code generiert und das Füllen der Objekte bei Folgeanfragen deutlich beschleunigt. Von mir gibt es dazu aber kein Sample-Code, es gibt dazu schon massig Infos im Web. Hier nur 2 ausgewählte Adressen:

LINQ to SQL - compiled queries

Solving common problems with Compiled Queries in Linq to Sql for high demand ASP.NET websites

In meinem aktuellen Projekt konnten wir durch den Einsatz von Compiled Queries an gezielten Stellen richtig viel sparen. Ich kann die gesparte Zeit nicht quantifizieren, aber beim Profilen hat man deutlich gesehen, dass alle Datenabrufe um ein vielfaches schneller waren.

Network IO

Ein massgeblicher Einflussfaktor bei vielen modernen Anwendungen ist der Netzwerkverkehr. Grundsätzlich gibt es 2 Regeln für den  Netzwerkverkehr

  1. so wenig wie möglich an Daten transportieren
  2. möglichst viel mit einem Rutsch, wenige Roundtrips (Chatty Interfaces)

Grundsätzlich sollte man bei allen Netzwerkstrecken prüfen, ob nicht die Datenmenge mittels Komprimierung reduziert und so effektiver übertragen werden kann.

Im IIS 6 kann die eingebaute Komprimeriung mittels der folgenden Zeilen aktiviert werden:

   1: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/parameters/HcDoDynamicCompression true
   2: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/GZIP/HcScriptFileExtensions asmx dll asp aspx ashx exe svc
   3: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/Deflate/HcScriptFileExtensions asmx dll asp aspx ashx exe svc
   4: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/parameters/HcDoStaticCompression true
   5: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/GZIP/HcFileExtensions html htm css js xml xslt xsd log
   6: cscript c:\Inetpub\AdminScripts\adsutil.vbs set w3svc/filters/compression/Deflate/HcFileExtensions htm css js xml xslt xsd log
   7: iisreset

Wahrscheinlich funktionieren die Zeilen auch im IIS7, das habe ich allerdings noch nicht geprüft. Hier kann die Komprimierung auf jeden Fall leicht auch per Webinterface aktiviert werden.

Für WCF sollte man sich mal das WCF Extension Projekt auf Codeplex ansehen.

WCF Services

WCF ist schon eine Weile mein Nummer eins Thema. Es macht jedes mal Spass mit WCF zu spielen, klar gibt es öfter auch mal Wutanfälle, meistens ist nicht WCF schuld. Eine Sache, bei der WCF einfach schwierig ist, ist das saubere Abräumen/Aufräumen. In WCF-Service Proxies verhält sich die Dispose-Methode nicht, wie in anderen IDisposable-Komponenten, WCF-Service Proxies werfen beim Dispose eine Exception, wenn der Client im Faulted-State ist. Daher sollte man nicht das Using-Pattern implementieren, sondern sollte den Proxy gezielt schließen, wenn es zu einem Fehler kommt, dann sollte man die Kommunikation mittels Abort() abrechen. Eine nette Implementierung für dieses Problem kann man bei Erwyn van der Meer “WCF Service Proxy Helper” sehen. (weiterer Artikel zum Disposing: Disposing a WCF Proxy)

Ich bin ein absoluter verfechter der strikten Entities, damit meine ich alle WCF-Entities, die explicit mittels DataContract markiert werden. Durch das explizite Markieren werden keine ungewollten/unnötigen Daten transportiert. Man kann so außerdem etwas Einfluss auf die Datenmenge nehmen, in dem Standardwerte nicht transportiert werden. Mittels der Eigenschaft EmitDefaultValue kann genau dieses Verhalten verändert werden. WCF ist an sich außerdem sehr schlau, was die Serialisierung und Transport von Daten betrifft. Dies trifft vor allem auf properitären Protokolle mit dem BinaryFormatter zu. Daher würde ich immer empfehlen auch mindestens ein NET-TCP-Binding Endpoint bereitzustellen, so dass .NET Applikation von den internen Mechanismen stark profitieren können.

GC (Garbage Collection)

Kann man am GC etwas optimieren? Nicht viel, es gibt aber eine Einstellung, die die Anwendung positiv beeinflussen können. Man kann sich in jeder Anwendung entscheiden, ob man Workstation GC oder Server GC benutzt. Der Unterschied von beiden GCs ist nur maginal, bei der Server GC findet das Aufräumen in einem eigenen Thread pro CPU statt. Es gibt wahrscheinlich noch weitere Unterschiede, aber das ist der, den ich mir auch merken kann. Man kann den Server GC leicht mittels des Konfigurationsblocks anlegen:

   1: <configuration>
   2:     <runtime>
   3:         <gcServer enabled=“true"/>
   4:     </runtime>
   5: </configuration>

Hier noch ein schöner Artikel zu dem Thema: http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx

Memory consumption

Irgendwas wollte ich hier noch reinpacken, wenn es mir wieder einfällt, dann trage ich es nach.

Dienstag, Juni 16, 2009

ASP.NET MVC Performance

Ich bin gerade beim “Bing”en auf eine super Präsentation zum Thema Performance mit ASP.NET MVC gestoßen. Ich kann die Folien nur empfehlen. Auf SlideShare kann man sich die Folien unter http://www.slideshare.net/rudib/aspnet-mvc-performance anschauen oder auch herunterladen. Es geht auch kurz um Omptimierungen in Linq-Queries.

Vielleicht sollte ich auch mal an dem fast 2 Monate alten Artikel zum Thema Performance weiterschreiben, …

Sonntag, April 26, 2009

Linq To Sql – Eager(/Lazy) Loading mit Einschränkungen

Die Woche haben wir im Projekt mal wieder eine Sonderaufgabe für Linq To Sql gefunden, aber dazu komme ich noch.

Wir nutzen intensiv Linq To Sql allerdings machen wir kein Lazy Loading, sondern laden unsere benötigten Objekte komplett (eager loading). Das kann man am einfachsten mit der LoadWith-Option in Linq to Sql machen.

   1: var query = from m in    db.ChildEntities
   2:             select m;
   3: var options = new DataLoadOptions();
   4: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
   5: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
   6: db.LoadOptions = options;

Diese Variante nutzen wir fast überall, allerdings haben wir zum Teil den Wunsch die Daten der Child-Entities einzuschränken. LoadWith würde alle verknüpften Elemente sofort mit laden, manchmal benötigt man nur einen bestimmten Teil der Daten. Somit macht es aus dem Performance-Gesichtspunkt und der Ressourcen-Optimierung viel Sinn nur die erforderlichen Daten zu laden. Durch AssociateWith kann man eine Einschränkung für das Laden der Daten definieren.

   1: var query = from m in    db.ChildEntities
   2:             select m;
   3: var options = new DataLoadOptions();
   4: options.AssociateWith<ChildEntities>(m=>m.ChildChildEntity.Where(c=c.Date > DateTime.UtcNow.AddDays(-60)));
   5: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
   6: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
   7: db.LoadOptions = options;

Wie schon gesagt, kann man auf die LoadWith definition verzichten, in dem Fall hätte man das Lazy Loading eingeschränkt. Eine super Einführung in Linq To Sql Eager/Lazy Loading hat Hilton Giesenow in seinem Blog geschrieben.

Nun kam aber der zweite Teil der etwas Tricky war. Wir wollten nun mehrere Einschränkungen setzen. Eigentlich eine typische “In” Anweisung in einem SQL-Statement. Bei uns scheiterten die Versuche immer wieder, da half nur noch alles einen Tag liegen zu lassen und nächsten Tag sich das Problem noch mal anzuschauen. Schließlich muss es gehen, wir haben in Anfragen bereits an anderen Stellen mit Linq To Sql ausgeführt. Letztendlich hat uns der “Suchanbieter unseres Vertrauens” (Google) zu der Lösung des Problems geführt. John Liu hatte ein ähnliches Problem und es einfach in einem kurzen Beispiel dargestellt. Man darf nicht mit IList bei der Übergabe arbeiten, sondern muss IEnumerable-Interface nutzen.

   1: var query = from m in    db.ChildEntities
   2:             select m;
   3: var options = new DataLoadOptions();
   4: options.AssociateWith<ChildEntities>(m=>en.Contains(m.ChildChildEntity.Date));
   5: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
   6: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
   7: db.LoadOptions = options;

Ich habe gestern Abend mal versucht eine Umwandlung der Statements in Linq To Entities gegoogled. Am Besten waren die Anweisungen auf dem ADO.NET-Team Blog, leider habe ich für die AssociateWith-Anweisung aber keine Entsprechung gefunden.

Mittwoch, April 22, 2009

SOA Conference 2009 Videos and Slides

Ich bin die Woche über einen anderen Blog-Eintrag auf die Live-Spaces der SOA Conference 2009 aufmerksam geworden, die Spaces sind unter http://soaconference2009.spaces.live.com angelegt. Hier gibt es sehr nette Videos und auch die PPT(X)s zu den Themen. Unter anderem gibt es Vorträge zu Dublin, Oslo und was sonst alles mit dem .NET-FX vorhanden ist, aber es gibt auch grundsätzliche Vorträge, wie an SOA-Entwicklung herangegangen werden kann.

Montag, März 30, 2009

WCF-PubSub Experiment

PubSub (Publish-Subscribe) kann man sehr gut dort einsetzen, wo eine beliebige Anzahl von Empfängern von Nachrichten existiert. Ab und zu wird PubSub auch als Observer-Pattern bezeichnet. Durch PubSub sollen alle die Interessiert sind, die Informationen der Veröffentlichung (Publish) erhalten. Der Vorgang der Veröffentlichung ist als asynchroner Mechanismus konzipiert, es kann allerdings auch synchron benutzt werden (wird aber nicht empfohlen). Aufgrund der asynchronen Ausführung ist der Einsatz einer Message Queue in vielen Anwendungsszenarien empfehlenswert. Eine Message Queue bringen viele Windows Server Systeme bereits mit (Msmq), so dass meistens keine weiteren Kosten anfallen, alternativ kann auch eine Datenbank verwendet werden.

Binding, die Duplex-Verbindungen unterstützen, sind:

  • WSDualHttpBinding
  • NetTcpBinding
  • NetNamedPipeBinding
  • NetPeerTcpBinding
  • NetTcpContextBinding

Auf der MSDN-Seite ist eine sehr gute Übersicht über die gebräuchlichsten Bindings und deren Fähigkeiten.

Mein Beispiel, hier der Download, ist nicht sehr sinnvoll aber es zeigt die grundsätzlichen Funktionen und einige Problemecken.

Ich habe ein sehr recht einfaches Klassenmodell, es werden simple mathematische Operationen in den Services durchgeführt. Es gibt einen Service zum Addieren und einen zum Multiplizieren. Es gibt 4 Service-Interfaces IMathAddService, IMathMultiplyService, ISubscriptionService und IPublishService. Die ersten beiden Services klammere ich aktuell etwas aus, entscheidend ist der ISubscriptionService bei dem sich alle Aufrufer (Subscriber) registrieren, um über Zustandsänderung/Veröffentlichungen informiert zu werden. In meinem Fall implementieren sowohl die Subscriber als auch der SubscriptionService das IPublishService-Interface. Es wäre nicht notwendig, dass der SubscriptionService das Interface implementiert, es macht es in meinem Fall aber einfacher. Durch die Publish-Methode im SubscriptionService werden die Veröffentlichungen angestoßen. Der SubscriptionService führt Veröffentlichungen allerdings nicht sofort aus, sonder stellt diese in eine Queue, da ich immer schön nacheinander eine Abarbeitung durchführen möchte. Die Queue ist im SubscriberManager mit implementiert, typischerweise würde sich hier ein MessageQueuing-System anbieten.PubSub-Demo class diagrammEs passiert nicht allzu viel in der Anwendung. Es wird zuerst die Endpoint-Konfiguration erstellt und das Binding gesetzt. Ich verwende NetTcpBinding um mit den verschiedenen Services zu kommunizieren. Im nächsten Schritt (Zeilen 12-16) werden die Instanzen der Subscriber-Channel erstellt, diese bekommen als Informationen den InstanceContext, der auf die Instanz des Callback zeigt. Nach der Erstellung der Hosts für meine 3 Services (Zeilen 18-29) werden die beiden Subscriber am Service registriert (Zeilen .31-34). Innerhalb des Using-Blocks wird die eigentlich Abarbeitung durchgeführt. Der Monitor ist meine Arbeitsklasse für die veröffentlichten Nachrichten. Ich wollte auch etwas die Konkurrenzproblematik bei meiner Anwendung zeigen, dazu rufe wird 2 mal hintereinander eine Veröffentlichung ausgeführt und sofort danach die eine weitere Rechenoperation gestartet. Die Mathe-Services speichern immer das letzte Ergebnis und setzen es bei einem Publish-Aufurf auf NaN (Not a Number).

   1: //setup endpoints
   2: EndpointAddress addressAdd = 
   3:     new EndpointAddress("net.tcp://localhost:5554/pubsub/add");
   4: EndpointAddress addressMultiply = 
   5:     new EndpointAddress("net.tcp://localhost:5554/pubsub/mutliply");
   6: EndpointAddress addressPubSub = 
   7:     new EndpointAddress("net.tcp://localhost:5554/pubsub/register");
   8: //binding with duplex support is required! (WSDualHttpBinding, NetTcpBinding, ..)
   9: NetTcpBinding binding = new NetTcpBinding();
  10:  
  11: //create the channels to register the subscribers (link to subscriber interface)
  12: DuplexChannelFactory<ISubscriptionService> duplexAddService, duplexMultiplyService;
  13: duplexAddService = new DuplexChannelFactory<ISubscriptionService>(
  14:     new InstanceContext(new MathAddService()), binding, addressPubSub);
  15: duplexMultiplyService = new DuplexChannelFactory<ISubscriptionService>(
  16:     new InstanceContext(new MathMultiplyService()), binding, addressPubSub);
  17:  
  18: //create all host and start them
  19: ServiceHost hostAdd = new ServiceHost(typeof(MathAddService));
  20: ServiceHost hostMultiply = new ServiceHost(typeof(MathMultiplyService));
  21: ServiceHost hostSubscribe = new ServiceHost(typeof(MemoryPubSubService));
  22: hostAdd.AddServiceEndpoint(typeof(IMathAddService), binding, addressAdd.Uri);
  23: hostMultiply.AddServiceEndpoint(typeof(IMathMultiplyService)
  24:     , binding, addressMultiply.Uri);
  25: hostSubscribe.AddServiceEndpoint(typeof(ISubscriptionService)
  26:     , binding, addressPubSub.Uri);
  27: hostAdd.Open();
  28: hostMultiply.Open();
  29: hostSubscribe.Open();
  30:  
  31: //register!
  32: ISubscriptionService dupAdd = duplexAddService.CreateChannel();
  33: dupAdd.Subscribe(PublishTopics.All);
  34: duplexMultiplyService.CreateChannel().Subscribe(PublishTopics.All);
  35: //run the watcher (async processor)
  36: using (PublishMonitor monitor = new PublishMonitor())
  37: {
  38:  
  39:     ChannelFactory<IMathAddService> addFactory = 
  40:         new ChannelFactory<IMathAddService>(binding, addressAdd);
  41:     ChannelFactory<IMathMultiplyService> multiplyFactory = 
  42:         new ChannelFactory<IMathMultiplyService>(
  43:         binding, addressMultiply);
  44:     IMathAddService add = addFactory.CreateChannel();
  45:     IMathMultiplyService multiply = multiplyFactory.CreateChannel();
  46:  
  47:     Console.WriteLine("Adding 1+2=" + add.Add(1, 2));
  48:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  49:                       multiply.GetLastResult());
  50:     Console.WriteLine("Calling publish!");
  51:     //this call should be normally done by the service itself
  52:     dupAdd.Publish(new PublishContext()
  53:                        {
  54:                            Topic = PublishTopics.Add, SomeDetail = "Some one to reset!"
  55:                        });
  56:     dupAdd.Publish(new PublishContext()
  57:                        {
  58:                            Topic = PublishTopics.Multiply, SomeDetail = "Some want's to reset again!"
  59:                        });
  60:     //show some concurrency probs, that can occure
  61:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  62:                       multiply.GetLastResult());
  63:     Console.WriteLine("Adding 4*2=" + multiply.Multiply(4, 2));
  64:  
  65:     Thread.Sleep(2000);
  66:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  67:                       multiply.GetLastResult());
  68:     Console.WriteLine("Finished sample, Press [Enter]");
  69:     Console.ReadLine();
  70:     Console.WriteLine("closing proxies and hosts");
  71:     addFactory.Close();
  72:     multiplyFactory.Close();
  73: }
  74: //close all and cleanup
  75: duplexAddService.Close();
  76: duplexMultiplyService.Close();
  77: hostSubscribe.Close();
  78: hostAdd.Close();
  79: hostMultiply.Close();

Wird das Ganze ausgeführt, so erhalte ich zum Beispiel auf meinem Dual Core das folgende Ergebnis:

PubSub-Demo output Je nach Lust und Laune des Prozessors kann das Ergebnis der “LastResult of”-Abfragen immer mal etwas anders aussehen, das ist in dem Beispiel von mir durchaus so gewollt, um Probleme der asynchronen Verarbeitung aufzuzeigen.

Perfekt ist die Implementierung meines Beispiels nicht, allerdings soll es auch nur einige Möglichkeiten und Probleme aufzeigen.

Hier noch einige interessante Links zu dem Thema:

Samstag, März 28, 2009

Earth Hour

Heute soll mal wieder ein Zeichen für den Umweltschutz gesetzt werden. Dazu soll jeder heute zwischen 20:30 und 21:30 auf jegliche unnötige Beleuchtung verzichten. Ich werde mich bemühen möglichst viele Verbraucher abzuschalten, allerdings habe ich fast nur Energiesparlampen. Ich hoffe nur, dass unser Stromnetz damit klar kommt, wenn alle plötzlich viel weniger Energie verbrauchen, mal schauen, ob ich auch ein Foto von der Gegend hier zu Stande bekomme.

Ach das Energiesparen wird vermutlich sehr interessant, da auch noch die Lange Nacht des Shoppings ist, also da muss es doch ein besseres Wochenende geben.

Detailierte Informationen erhält man auf der Website von Earth Hour.

Update:

Tja, hier in Lichtenberg hat man von der Earth Hour nix gemerkt, auch in Marzahn ist keine Veränderung zu sehen gewesen. Ich hatte einige Fotos gemacht, aber es ist einfach kein Unterschied zu sehen. Sicherlich ist das Ganze eher ein Symbolischer Akt statt wirklich effektiv einen Nutzen zu haben. Sind nicht auch kleine Gesten wichtig?

Lichtenberg 20:20Lichtenberg 20:33

Sonntag, März 22, 2009

Subversion 1.6 ist da

Noch ein kleiner Beitrag zu guten Tools. Dieses Wochenende wurde außerdem noch Subversion 1.6 und TortoiseSvn 1.6 released. Die interessanteste Neuerung von Subversion Repository Packaging. Interessant wird nun, wann die geeignete Zeit für ein Upgrade unserer Projektumgebungen gekommen ist. Ich gehe davon aus, dass es wie immer ohne größere Probleme abläuft, allerdings die Zeit für das Upgrade (svnadmin upgrade repo) die Komprimierung doch wieder etwas dauert.

PowerShell – gar nicht so schlecht

Ich habe mir ein kostenloses eBook zur PowerShell von Keith Hill besorgt und mich mal ein bisschen damit beschäftigt. Endlich habe ich einiges verstanden und nach einigen Sessions versteht man auch die Zusammenhänge etwas. Die Commands sind noch nicht so drin, wie in der DOS-Batch-Welt. Aber ich habe gelernt, dass das wichtigste Kommando “get-command” ist, danach kommt wahrscheinlich schon “get-member”, dann kann man sich so langsam durch die optionen hangeln. Ab und an hilft vielleicht auch “get-help”, bei “get-help” kommen auch die beiden Kommandos in den remarks als Beispiel.

Für WCF habe ich in der Präsentation von Christian Weyers auch etwas Nettes gefunden “get-wmiobject” oder auch “gwmi”:

   1:   $ms = get-wmiobject -class "AppDomainInfo" -namespace "root\servicemodel" -computername "." | where {$_.Name -eq "myservice.exe"}
   2:   $ms.TraceLevel = "Warning, ActivityTracing"
   3:   $ms.Put()

Für dieses Wochenende reicht es mir aber mit Technikthemen. Ich werde mal versuchen die restlichen Stunden zu nutzen, um endlich wieder fit zu sein.

WCF Tipps und Tricks

Letzte Woche gab es richtig gute Tipps von Christian Weyers zu verschiedenen WCF Themen. Die Folien können die Themen nur Anreisen, aber man bekommt zu dem die Folien und Sample-Code zum Download mit vielen Ressourcen. Jeder der sich mit WCF beschäftigt, sollte sich die Folien reinziehen.

Das ganze Thema Service Throttling habe ich allerdings noch nirgends richtig tiefgehend beleuchtet gefunden. Das Thema ist so komplex und auch service-spezifisch, dass es wahrscheinlich nicht wirklich einfach abzuhandeln geht.

Security gibt es leider gar keine Tipps, aber dafür gibt es andere Quellen und ist wie das Thema Service Throttling einfach extrem umfangreich und auch noch Anforderungsspezifisch.

Donnerstag, März 05, 2009

JavaScript (Frameworks) im Einsatz

Die letzten 2 Monate habe ich mich partiell mit Extrem JavaScript beschäftigt, eigentlich war es auch wieder nicht so extrem. Aber es war die Website mit dem meisten JavaScript, die ich bisher erstellt habe.

Dabei kamen unter anderem auch ComponentArt-Tools zum Einsatz. Im Großen und Ganzen nehmen diese recht viel ab. Allerdings stellt sich wie immer heraus, dass für die speziellen Wünsche ordentlich viel Code notwendig ist.

Das Customizen und Erweitern von Funktionen hat sich durch den Einsatz von jQuery stark vereinfacht, es aber notwendig die Möglichkeiten von jQuery möglichst komplett einzusetzen. Die Standardmöglichkeiten von jQuery sind schon sehr mächtig, hier sind vor allem die Manipulations- und Animationsmechanismen zu nennen. Es passiert leider immer wieder oft, dass man den Selector nicht korrekt angibt. Der Selector ist schon ein riesiges Thema für sich. Ein sehr guter Artikel zu jQuery ist im CoDe-Magazin veröffentlicht, den kann ich nur Empfehlen. Ebenso muss man wirklich die Dokumentation von jQuery loben.

$(<selector>) - $(„#id“) - $(„.cssClass“) – $(„element“)

Die Rückgabe jeder jQuery-Funktion ist ein jQuery-Object. In einem jQuery-Object findet man eine Liste mit den gefundenen Objekten, per Index kann jedes einzelne Zugegriffen werden. Es ist allerdings nicht notwendig auf jedes einzeln zuzugreifen, da jQuery-Funktionen auf alle Elemente in dem aktuellen jQuery-Objekt wirken. Durch $(„p“).css(„color“, „#f00“) erhalten alle p-Elemente die Vordergrundfarbe rot. Am meisten macht das „Spielen“ mit den Effekten Spaß, $(„.ajaxContent“).fadeOut(500,function(){$(this).fadeIn(500);}); - so flackert kurz der Inhalt. Sehr einfach ist es auch einen Parent mit bestimmtem Selector zu finden, hierzu muss die Methode parents verwendet werden. z. B. $(this).parents(<selector>).

Der Zugriff auf Webservices oder WCF-AjaxServices klappt am besten mit den Microsoft ASP.NET AJAX-Funktionen. Dazu muss der ScriptManager auf der Seite verwendet werden und anschließend der Service referenziert werden. 

   1:      <asp:ScriptManagerProxy ID="proxy" runat="server">
   2:          <Services>
   3:              <asp:ServiceReference Path="~/Ausschreibung/GridControl.svc" />
   4:          </Services>
   5:      </asp:ScriptManagerProxy>

Hinweis: JavaScript erlaubt keinen Zugriff auf andere Domains, so dass der Webservice nicht in einer anderen Domain und auch nicht auf einem anderen Server-Port laufen darf.

Außerdem ist noch das Type-System (Stichwort: prototype) mit den im Visual Studio hinterlegten Templates eine tolle Sachen. Es lassen sich mit den Templates recht leicht eigene JavaScript-Klassen erschaffen.

Visual Studio New Item Dialog - Ajax Templates

Etwas mehr nerven hat mich das Thema JavaScript-Events gekostet. Im Gegensatz zu .NET-Events referenziert this nicht das Objekt, dass sich registriert hat, sondern den Sender des Events. Sowohl mit jQuery als auch mit ASP.NET Ajax kann man allerdings die Informationen über den Empfänger (Registrar) mitgeben.

$(<selector>).bind(„click“, <myobject (this)>, function(event){var myobject=event.data});

$addHandlers(element,{click, onClick},myObject);

Jetzt noch einmal zurück zum ComponentArt-Grid, wir wollten eine hierarchische Darstellung des Grids, allerdings ohne auf Ajax zu verzichten. Derzeit unterstützt das Grid im WebService-Mode nur begrenzt diese Funktion. Durch den Artikel im Support-Forum hat es sich lösen lassen. Einige Tipps fehlen allerdings, wie verhält es sich mit Paging, was ist mit Sortierung, was ist mit …. Beim Laden der Objekte müssen diese auch in der Hierarchie der Grid-Level geladen werden. Nach einigen Bugs in meinem Code und einigen kleinen Fehler funktionierte anschließend auch das Paging, dazu ist wichtig, welche Properties gesetzt werden. Hier meine Erkentnisse:

    1. Größe der Seite setzen - grid1.set_pageSize(itemsWithinAPage);

    2. Anzahl der ignorierenden Einträge in der Ergebnismenge - grid1.set_recordOffset(0);

    3. Ergebnisse laden - grid1.load(resultArray);

    4. Setzen der Seitenzahl - grid1.set_pageCount(pagesCount);

    5. Endlich darstellen der Ergebnisse - grid1.render();

Ich musste leider feststellen, dass es gar nicht wichtig ist, wenn die Anzahl der Gesamtentreffermenge gesetzt wird, entscheidend ist das korrekte Setzen der Seitenzahl (Punkt 4)ä Ebenso muss die Property für die „GroupingPageSize“ groß genug sein, da sonst die Ergebnisse ohne Rückmeldung nicht mehr dargestellt werden.

Freitag, Februar 13, 2009

SQL Server 2008 Setup issue Vista x64

Die Woche habe ich mich nach einigen Erzählungen von einem Kollegen dazu entschlossen, die SQL Server 2008 Management Tools zu nutzen. Nach der Entscheidung gleich zu MSDN-Seite und das ISO (Dev-Version) gezogen, leider braucht das bei 4GB einiges an Zeit, wenn man nicht gerade am Deutschen Forschungsnetz hängt.

Den nächsten Tag habe ich dann mit der Installation los gelegt, alte Version der Management Tools deinstalliert, noch relativ Problemlos. Allerdings haben mich die ganzen verbleibenden “Leichen” und Reste etwas verwundert. Ich frage mich immer noch, was weiter zu deinstallieren ist. Anschließend das DVD-Image gemounted und die Installation gestartet. Überraschung, wieder eine neue Installer-Version, dabei fand ich die alte gar nicht schlecht, aber wie auch immer, mutig durch. Dann ging es los!

“Attribute do not match … “-Error nach der Auswahl der Komponenten. Der Fehler bezog sich auf das Zielverzeichnis des SQL Servers. Ok, so überrascht war ich allerdings von dem Fehler nicht, da ich den gleichen Fehler bereits von der SQL Server 2005 Installation kenne. Es ist nicht möglich den Server in komprimierten Verzeichnissen zu installieren. Also ohne Bedenken das Verzeichnis von der Komprimierung ausgenommen und erneut versucht. AH, immer noch der Fehler. Bei meinem 2. Versuch mit etwas verzogener Miene habe ich auf meinen gesamten “Program Files”-Verzeichnis die Komprimierung entfernt, wehe einer hat eine zu kleine Platte. Aber auch der Versuch scheitert. Installation neu gestartet, allerdings keine Besserung. Anschließend habe ich die Installation den Tag über nicht mehr angefasst und sie stand noch im gleichen Zustand. Abend mal so mögliche Optionen überlegt, auch Google bemüht (ich weiß, eigentlich hätte ich Live-Search verwenden müssen), allerdings waren die Texte nicht sehr hilfreich. Dann habe ich etwas probiert, was ich bei einer Microsoft Installation von einer x64-Software nicht erwartet hätte, es funktionierte. Die Lösung war einfach die Attribute vom “Program Files (x86)”-Verzeichnis zu löschen. Aber wo zur Hölle steht denn dieser Tipp!

Nach wenigen Minuten war die Installation abgeschlossen und die Tools ready. So, welchen Server migriere ich nach 2008? ….

Mittwoch, Februar 04, 2009

WPF data binding sheet

Wow, bin gerade auf ein sehr schönes data binding sheet zu WPF gefunden. Der Original post ist hier http://www.nbdtech.com/blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx zu finden. Ich habe mir das Dokument, ca. 300kbyte, gleich mal heruntergeladen und komme damit vielleicht noch besser mit dem data binding zu recht.