PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ASP.NET/C#]Multithreading


Gast
2011-12-07, 14:17:53
Hallo,

ich habe eine Anwendung, die ich als ASP.NET-Webseite realisieren will, d.h. die GUI als Web-Frontend und die Backend-Logik auf dem Server laufend. Die GUI soll einen Button und ein Label enthalten, wobei der Klick auf den Button einen Thread startet, der einmal pro Sekunde eine Variable hochzählt, die dann auf dem Label ausgegeben werden soll. Als Windows-Forms-Anwendung sähe das z.B. so aus:

partial class Form1 : public System.Windows.Forms.Form
{
// deklariere Event
delegate void ProgressDelegate(int progress);
event ProgressDelegate progressEvent;

void button1_Click(object sender, EventArgs e)
{
// installiere ShowProgress() als Event handler
progressEvent += new ProgressDelegate(ShowProgress);

// starte Thread, der threadProc() ausführt
ThreadStart ts = new ThreadStart(threadProc);
Thread thread = new Thread(ts);
thread.start();
}

// Funktion, die im Thread ausgeführt wird
void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
// löse Event aus
this.Invoke(progressEvent, new object[]{progress});
// warte 1 Sekunde
Thread.Sleep(1000);
}
}

// Event handler
void ShowProgress(int progress)
{
label1.Text = progress;
}
}

Im Thread wird 10 Sekunden lang einmal pro Sekunde die Variable progress um 1 erhöht und dann der Event progressEvent ausgelöst, wodurch die Funktion ShowProgress() aufgerufen wird, die den Wert von progress auf dem Label ausgibt.

In WPF sieht es fast genauso aus, Form1 ist dann nur halt nicht von public System.Windows.Forms.Form abgeleitet, sondern von System.Windows.Window, statt this.Invoke(...) steht da Dispatcher.Invoke(...), und den Text des Labels ändert man nicht mit der Property Text, sondern mit Content.

Aber wie macht man es in ASP.NET? Form1 leitet sich dann von System.Web.UI.Page ab, soweit klar, aber wie ändert man vom Thread aus den Text des Labels? Die Page-Klasse hat keine eigene Invoke()-Methode, und eine Dispatcher-Klasse wie in der WPF-Variante gibt es auch nicht. Ich habe schon einen direkten Aufruf von ShowProgress() versucht, etwa so:

void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
ShowProgress(progress);
// warte 1 Sekunde
Thread.Sleep(1000);
}
}

was interessanterweise auch überhaupt nicht zu einem Laufzeitfehler führt, aber der Effekt ist der, dass der im Webbrowser zu sehende Text des Labels gar nicht geändert wird. Laut Debugger wird die Codezeile in ShowProgress() zwar durchlaufen, aber es hat keine Auswirkung auf den angezeigten Text des Labels.

Wie muss man das richtig machen?

Ich habe schon hier nachgesehen:

http://www.codeproject.com/Articles/38501/Multi-Threading-in-ASP-NET

was davon zu zeugen scheint, dass es für ASP.NET ein eigenes Threading-Modell abseits von System.Threading.Thread gibt. Allerdings scheint das für meine Zwecke nicht passend zu sein. Wenn ich das richtig sehe, ist die PageAsyncTask-Klasse so eine Art Pendant zur Thread-Klasse, und die Methoden BeginAsyncOperation() und EndAsyncOperation() werden beim Starten und Beenden des "Threads" ausgeführt. Was ich vermisse, ist eine Funktion, die während des asynchronen Tasks ausgeführt wird.

Ich könnte mir natürlich auch noch vorstellen, dass das, was ich vorhabe, gar nicht realisierbar ist. Allerdings würde das meiner Meinung nach der offensichtlich von Microsoft verfolgten Strategie, Webentwicklung und lokale Anwendungsentwicklung zu vereinheitlichen, widersprechen.

Unfug
2011-12-07, 16:49:42
Ich lehn mich mal weit aus dem Fenster, da es etwas länger her ist mit ASP.NET bei mir.

Zunächst:
ASP.NET wird geparst --> Code auf dem Server wird in HTML umgesetzt und an den Aufrufer (Browser) zurückgesendet.

Für jede erneute Änderung, die der Aufrufer sehen soll, muss also die Seite (oder ein Teil davon) neu geladen werden.

Bei ASP.NET geht dies mit Update Panel. Man definiert ein UpdatePanel Bereich wo man z.B. ein Label einfügt. Dann stellt man ein, dass das UpdatePanel jede Sekunde aktualisiert werden soll (also vom Server neu geladen).

Den Text holt sich das Label dann neu vom Server.

Ich denke mit dem Stichwort: UpdatePanel wirst du fündig.

Gast
2011-12-07, 18:32:39
Danke, werde ich mir mal anschauen.

][immy
2011-12-07, 22:01:25
mit einem Updatepanel ging das (auch wenn es nicht schön ist), aber du solltest dich erst mal richtig mit ASP.net auseinander setzen und die funktionsweise verstehen bevor du etwas mit dem updatepanel machst.

wie schon geschrieben wurde, du hast bei asp.net keinen main-thread wie in windows forms, sondern du machst einen request an einen server und dort hast du nen thread für dich allein. Hier findet noch kein rendering oder sowas statt, weil der code läuft ja auf dem server und nicht auf dem client.

alles was du zum client zurück schickst ist html. welches letztendlich vom browser (client) gerendert wird.
was du hier bräuchtest um dein beispiel zum laufen zu bringen wäre eher nicht asp.net sondern in diesem anwendungsfall wäre javascript eher deine wahl.

natürlich kannst du mit hilfe des update-panels und einem timer control eine ähnliche wirkung erzielen, aber das wäre weder schön noch besonders schonend.
das updatepanel verschleiert an sich nur den postback. dieser kommt z.B. wenn du auf einen butten klickst, die seite zum server geschickt wird (bzw. die entsprechenden daten) und eine quasi neue seite zurückkommt die der browser dann rendert. Das Updatepanel greift hier zwischen und fängt z.B. ein solchen klick-event ab. macht aber trotzdem noch immer den gleichen mist im hintergrund, wertet dann aber mit hilfe von javascript hinterher die daten aus um dann z.B. neue controls aufzubringen, daten zu ändern,.... Auf diese weise sieht der nutzer keinen refresh der seite wie es bei einem postback der fall wäre. sparen tut es allerdings absolut nichts.


achja, multithreading ist zwar in asp.net auch weiterhin möglich, aber dies sollte man sehr genau abwägen. denn jeder request auf an den server startet einen neuen thread und so kann es schnell passieren das dir die threads im threadpool ausgehen und auf diese weise andere threads warten müssen. du kannst zwar auch threads am .net threadpool vorbei erzeugen, aber die beschränkte größe der gleichzeitig laufenden threads hat schon seine gründe (zu viele threads machen können sich auch gegenseitig blockieren).

Gast
2011-12-08, 14:04:39
[immy;9068940']mit einem Updatepanel ging das (auch wenn es nicht schön ist), aber du solltest dich erst mal richtig mit ASP.net auseinander setzen und die funktionsweise verstehen bevor du etwas mit dem updatepanel machst.

wie schon geschrieben wurde, du hast bei asp.net keinen main-thread wie in windows forms, sondern du machst einen request an einen server und dort hast du nen thread für dich allein. Hier findet noch kein rendering oder sowas statt, weil der code läuft ja auf dem server und nicht auf dem client.

alles was du zum client zurück schickst ist html. welches letztendlich vom browser (client) gerendert wird.ja, das wird mir auch langsam klar. Bei aller Ähnlichkeit, die die Webentwicklung unter .NET mit der lokalen Anwendungsentwicklung animmt, ist und bleibt eine ASP.NET-Webseite eine traditionelle Webseite, wo der Client einen Request an den Server sendet und der Server eine Response zurückschickt. Dass der Server von sich aus Daten an den Client sendet, ist offenbar nicht vorgesehen, und damit ist mein Vorhaben nicht umsetzbar.

Ok, danke für die Hinweise.

Threadersteller
2011-12-22, 17:43:32
Hi, ich bin's nochmal.

Ich hätte da nochmal ne Frage. Es gibt ja Webchats, d.h. Chats die nicht in einer eigenen Chatsoftware laufen wie MSN, ICQ & co., sondern im Webbrowser. Und darunter gibt's auch solche, wo man nicht ständig den Reload-Button klicken muss, um neue Nachrichten zu sehen, sondern wo die auch scheinbar autonom ankommen. Ich habe da mal ein bisschen nachgeforscht und gelesen, dass solche Chats z.B. mit Ajax realisiert werden können. Im Wiki-Artikel zu Ajax habe ich dann folgendes Schaubild gefunden:

http://de.wikipedia.org/wiki/Datei:Prozessfluss-ajax.svg

Demnach bleibt auch bei Ajax das Request-Response-Prinzip bestehen, d.h. der Server kann nur auf Requests von der Client-Seite antworten, jedoch läuft auf Client-Seite im verborgenen die Ajax-Engine, die autonom, also ohne vom Benutzer dazu angestoßen zu werden, in regelmäßigen Intervallen eine Anfrage an den Server sendet, ob neue Daten da sind.

Bedeutet das nicht, dass Ajax im Grunde das gleiche macht, was auch so ein UpdatePanel mit einem Timer drin machen würde, und somit eine ähnlich hohe Netzlast erzeugt?

][immy
2011-12-22, 21:54:59
Hi, ich bin's nochmal.

Ich hätte da nochmal ne Frage. Es gibt ja Webchats, d.h. Chats die nicht in einer eigenen Chatsoftware laufen wie MSN, ICQ & co., sondern im Webbrowser. Und darunter gibt's auch solche, wo man nicht ständig den Reload-Button klicken muss, um neue Nachrichten zu sehen, sondern wo die auch scheinbar autonom ankommen. Ich habe da mal ein bisschen nachgeforscht und gelesen, dass solche Chats z.B. mit Ajax realisiert werden können. Im Wiki-Artikel zu Ajax habe ich dann folgendes Schaubild gefunden:

http://de.wikipedia.org/wiki/Datei:Prozessfluss-ajax.svg

Demnach bleibt auch bei Ajax das Request-Response-Prinzip bestehen, d.h. der Server kann nur auf Requests von der Client-Seite antworten, jedoch läuft auf Client-Seite im verborgenen die Ajax-Engine, die autonom, also ohne vom Benutzer dazu angestoßen zu werden, in regelmäßigen Intervallen eine Anfrage an den Server sendet, ob neue Daten da sind.

Bedeutet das nicht, dass Ajax im Grunde das gleiche macht, was auch so ein UpdatePanel mit einem Timer drin machen würde, und somit eine ähnlich hohe Netzlast erzeugt?

Also im grunde schon.

Ajax ist aber nur eine technologiebeschreibung die nur bedeutet das du mit javascript requests machst und xml/json zurück bekommst und und dieses wieder mit javascript verarbeitest.
Das Updatepanel ist also eine Ajax basierendes Control. Allerdings ist das Updatepanel mehr oder minder ein worst-case szenario. Es wird eigentlich nur ein normaler postback gemacht und die seite wird dann mittels javascript gefüllt anstatt komplett neu gerendert.

Das Timer-Control würde also im gewünschten intervall immer wieder alles auf der seite senden.

Es ist sehr viel besser (da gibt es einige control rad toolkits (telerik, devexpress,... die hier einiges an arbeit abnehmen) javascript dazu zu nutzen z.B. einen webservice anzufragen und dabei immer nur die information zu senden und zu empfangen die nötig für die aufgabe sind.
das ist allerdings sehr aufwändig. von daher sollte man sich vorher fragen wie viel zeit man in die entwicklung stecken will/kann.
zudem (zumindest ist das mein empfinden) ist besonders die javascript-entwicklung sehr sehr zeitaufwendig und hier solltest du dir mit bibliotheken wie z.B. jquery oder dojo behelfen, diese nehmen dir sehr viel arbeit ab sind cross-browser kompatibel und normalerweise auch noch sehr schnell in der ausführung.

Das ganze lässt sich aber wohl kaum hier in einem forenpost beantworten, da musst du jede menge zeit und gehirnschmalz reinstecken um da durchzublicken. und wenn du grade denkst alles kapiert zu haben kommt sowieso wieder irgendein browser update wodurch fehler auftauchen und du dich wieder fragen darfst wozu es w3c standards überhaupt gibt :freak: