Fragensteller
Parallele Aufrufe einer Methode in einer Warteschlange schicken und nacheinander abarbeiten...

Allgemeine Diskussion
-
Hallo zusammen,
ich habe eine Methode, welche einen Code ausführt, welcher nicht sonderlich gut für parallele Aufrufe optimiert ist. Diese Methode wird aber mehrfach zugleich aufgerufen (via Webservice) und macht Probleme.
Ich würde gerne versuchen, alle Aufrufe dieser Methode in eine Warteschlange zu stecken und sie nacheinander aufzurufen (mögliche Laufzeit- und Performanceprobleme lassen wir mal außen vor).
Was wäre denn ein guter Weg, um so was zu erreichen. Die Aufrufer dieser Methode sollen nichts davon mitbekommen, außer vielleicht, dass es ein wenig dauert, bis das Ergebnis zurückkommt.
Gruß, Karsten.
- Typ geändert Dimitar DenkovMicrosoft contingent staff, Administrator Freitag, 29. Dezember 2017 14:35 Warten auf Rückmeldung
Alle Antworten
-
Hi Karsten,
grundlegend solltest du die Methode bei einem Webservice so gestalten, das sie keine thread übergreifenden Abhängigkeiten hat. Alles andere macht langfristig nur Probleme.
Als Workaround kannst du Monitor.TryEnter,Lock oder Interlock (welches da jetzt genau die Richtige Methode ist musst du Mal googlen.) vor dem Methoden Aufruf verwenden, es spät den zugriff solange bis das lockObjekt freigegeben wurde.
Für den Webservice brauchst du da keine Warteschlange (die zwischen den Verschiedenen Aufrufern zu Synchronisieren und dann an die Passenden Threads wieder das Richtige Ergebnis zurück zu liefern, denke ich wird auch kein Spaß sein) , alle anderen Aufrufe müssen dann aber warten. Ich bin mir da aber jetzt nicht sicher ob es da nicht zu Deadlocks und Racebedingungen kommen kann. Ich wäre also mit dem Konstruktiv sehr vorsichtig.
Hier vielleicht noch ein paar Links dazu:
Empfohlene Vorgehensweise für das verwaltete Threading
Volatile vs. Interlocked vs. lock -
Hallo,
die (Remote-)Aufrufe einer Methode über einen Webservice starten diese ja normalerweise in verschiedenen Threads. Am Besten erscheint mir daher, du machst die Methode "threadsicher". Falls das nicht geht, würde ich so vorgehen:
1.) Der Client sendet ein DTO wird mit den erforderlichen Parametern.
2.) Der Webservice gliedert dieses DTO (threadsicher) in eine (static) RequestQueue<DTO> und bestätigt dies als Antwort mit einer ID, ggf. mit einer Abschätzung der Bearbeitungsdauer oder sonstiger Infos.
3.) Der Server gliedert die Resultate der Bearbeitung in eine ResponseListe/Dictionary.
4.) Der Client fragt periodisch nach, ob zu seiner ID ein Resultat vorliegt und holt dies ggf. unter Entfernung (threadsicher) aus der ResponseListe ab.Der Server kann auch periodisch die vergessenen und vergammelnden Resultate bereinigen.
Passende Listen finden sich auch hier.
Was ich also nicht machen würde: Den TimeOut-Wert zu erhöhen und direkt (und ggf. bis in alle Ewigkeit) auf die Bearbeitung und Rückantwort warten.
Das ist jetzt nur eine grobe Idee, die sich im konkreten Fall bestimmt noch optimieren lässt.
Gruß -
Hallo zusammen,
vielen Dank für eure beiden Antworten. Beide Lösungsvorschläge klingen sehr kompliziert und erzeugen möglicherweise weitere Seiteneffekte. Ich denke, mir bleibt nichts anderes übrig, als die vom Webservice aufgerufenen Methode so abzusichern, dass sie beim parallelen Betrieb sich nicht gegenseitig beeinflussen.
Nichts desto trotz lese ich mir die empfohlenen Links nochmal durch.
Danke und Gruß, Karsten.
-
Hallo Karsten,
ich hoffe mal, Du arbeitest nicht mit statischen Klassen/Objekten und bei statischen Methoden greifst Du nicht auf globale Objekte zurück, die nicht threadsicher sind. Falls doch, solltest Du das komplett entfernen und nur noch instanz/requestbezogene Objekte verwenden.
Statische Objekte sind generell wie Application Variablen zu sehen, diese gelten anwendungsweit für _alle_ Requests _aller_ Clients.
Statische Objekte sind in ASP.NET erst einmal generell böse, wenn man nicht weiß, was man tut. Oft wird aus "Einfachheitsgründen" eine Connection als:
Public Shared Property Connection As SqlConnection
oder ähnliches eingebaut. Dass das in lokalen Anwendungen wie WinForms geht, liegt in der Regel daran, dass eben auch nur ein gleichzeitiger Zugriff erfolgt (aber selbst da natürlich auch nicht immer).
Webanwendungen, auch ASP.NET Anwendungen, sind aber u.U. sehr vielen gleichzeitigen Zugriffen ausgesetzt und da kommt man sich mit statischen Eigenschaften und Methoden sehr oft und sehr gerne in die Quere.
Letztendlich kann man sowas schon einsetzen, man muss aber wissen, was man tut.
Ein paar Infos hierzu findest Du hier:
http://www.aspnetzone.de/blogs/juergengutsch/archive/2007/08/24/statische-variablen-in-asp-net.aspx
http://stackoverflow.com/questions/8919095/lifetime-of-asp-net-static-variable
http://www.aspnetzone.de/forums/thread/200752.aspx
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Donnerstag, 14. Dezember 2017 09:26
-
Hallo Stefan,
genau das Problem der statischen Variablen trifft mich jetzt :-(
Zur Erklärung: Ich habe hier eine dicke Windows-Forms-Anwendung, wo ein Teil der Funktionalität jetzt via Webclient verfügbar gemacht wird. Also rufe ich die relevanten Funktionen über einen Webservice auf und falle prompt auf die Nase (sowie die Parallelität steigt). Ich habe mir ein Testprogramm geschrieben, wo mit Threads mein Service bombardiert wird und siehe, so ab 3-4 paralleler Threads kommt es zu den merkwürdigsten Fehlern.
Jetzt beiße ich grade in den sauren Apfel und schreibe bestimmte Routinen einfach komplett neu...
Servus, Karsten.
-
Hallo Karsten,
ich hab's befürchtet. Bei WinForms gibt es in der Regel ja nur eine Instanz und daher auch keine parallelen Aufrufe. Bei einer Webanwendung hat man es mit dem genauen Gegenteil zu tun. Teils 100e gleichzeitig eingehende Requests, die parallel verarbeitet werden müssen. Da sind statische Variablen in der Regel der GAU.
Es bleibt dir wirklich nichts anderes übrig als das an den betreffenden Stellen komplett umzuschreiben.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Tja, es sind ja nicht nur die statischen Variablen. Die betreffende WinForms-Anwendung verfügt auch noch über einen internen Cache, der dafür sorgt, dass bestimmte Daten über die gesamte Laufzeit hinweg im RAM bleiben. Frei nach dem Motto, wenn ein Fenster den Datensatz "A" lädt und ein anderes Fenster den gleichen Satz braucht, dann bekommt das nächste Fenster das gleiche Objekt zugewiesen und keine Kopie frisch aus der Datenbank. Klingt gut, ist aber die Hölle. Es bleiben regelmäßig Daten hängen und man muss dann normalerweise das Programm schließen und neu starten.
Beim Webserver potenziert sich dass dann noch, da es nun sehr viele "Clients" gibt, die sich jetzt die Daten teilen. Ich hatte hier in meinem Versuchen dann teils mehrere GB RAM Verbrauch, die natürlich auch nicht mehr entfernt wurden (außer durch Neustart des IIS).
Naja, ich kämpfe mich durch.
Servus, Karsten.
-
Hi Atlan,
wenn die Windows-Anwendung stabil laufen würde, dann würde ich vor dem gesamten Umbau die Datenzugriffsschicht mit dem Cache als Singleton in der Web-Anwendung laufen lassen. Es müssten dann lediglich die Methoden dieser Singleton-Instanz threadsicher sein, ggf. erst einmal nur mit synclock Da würden zwar die Response-Zeiten nicht optimal sein, aber es sollte erst einmal stabil laufen.--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks -
Hallo Atlan,
statische Methoden oder Felder sind nicht das "Böse". Beweis: Schon die Startmethode einer Winforms-Anwendung ist "static void Main()". Und die befindet sich auch noch in einer "static class Program". (Bitte jetzt nicht ganz ernst nehmen... :-)
Aber mal ernsthaft. Wenn ich bestimmte Daten innerhalb einer Anwendung global verfügbar haben möchte, ist das noch kein Design-Fehler. Als Beispiel nenne ich mal den Mehrwertsteuer-Satz, den ich beim Programmstart "einlesen" könnte und global verfügbar mache. Warum sollte ich den denn auch bei jeder Verwendung aus einer DB neu abrufen?
Es gibt diverse Daten, die über alle Sitzungen hinweg benötigt werden können. Beispielsweise die Ländertabelle zur Verwendung bei den Kundenstammdaten. In einer Webanwendung würde ich die genau dann laden, wenn sie nicht im Cache vorhanden ist. Konkret würde ich diese Liste in einer statischen Klasse in einem statischen Feld readonly ablegen. Jede Session/Client kann sie dann verwenden. Das ist im übrigen auch eine übliche Verfahrensweise.
Zur Verwendung statischer Felder (alternativ zur Application-Auflistung) siehe auch hier oder hier oder hier:
Das man also bestimmte Datensätze in einer Anwendung in einen "Cache" packt, ist nicht per Definition "schlecht". Um das für die in Rede stehende Anwendung beurteilen zu können, fehlt hier allerdings der Einblick. Wenn sich die Anwendung aufhängt, gibt es vermutlich eine fehlerhafte Implementierung bestimmter Funktionalitäten.
Wenn eine Ressource zwischen verschiedenen Threads (oder gar Prozessen) geteilt werden muss, hängt es auch von der Art der Ressource und der Aufgabe ab, wie konkurrierende oder parallele Zugriffe zu ermöglichen sind.
Wenn dein Webservice Speicher nicht freigibt, vermute ich hier einen Fehler in der konkreten Implementierung. Für die Freigabe nicht mehr benötigter Ressourcen sollte sich die Anwendung schon zuständig fühlen. Wieviel ist denn bei dir "sehr viele Clients"? Warum wird der RAM nicht freigegeben?
Die Fragestellung ist allerdings auch insgesamt sehr vage und deshalb wirst du vermutlich auch nur Allgemeines hier ernten können. Das Thema Multithreading, parallele Verarbeitung etc. ist bestimmt eines der komplexeren Themen.
Vielleicht kannst du die in Frage kommenden Funktionalitäten ja auch in eine eigenen Class-Library verbringen und somit gleichzeitig die Windows-Forms-Anwendung aufpäppeln. Ich persönlich würde zusehen, dass du für beide Anwendungen (Desktop & Webservice) eine gemeinsame Codebasis erstellst.
Es ist die Natur einer Webanwendung, von verschiedenen Clients mehr oder weniger parallel in Anspruch genommen zu werden. Die Verwendung von statischen Elementen scheint mir dabei auch nicht sonderlich selten sondern eher die Regel zu sein.
Gruß, K.
-
Hi,
Es ist die Natur einer Webanwendung, von verschiedenen Clients mehr oder weniger parallel in Anspruch genommen zu werden. Die Verwendung von statischen Elementen scheint mir dabei auch nicht sonderlich selten sondern eher die Regel zu sein.
eigentlich nicht. Die Elemente werden eher requestbezogen ermittelt, das ist in der Regel unproblematisch. Statische Eigenschaften sehe ich, wenn überhaupt, nur extrem selten. Statische Methoden, die threadsicher arbeiten, werden hingegen oft und gern verwendet. Module oder statische Klassen eigentlich gar nicht. Zumindest sind mir noch keine untergekommen.
Und natürlich sind unveränderliche Daten bzw. welche, die für alle Requests identisch sein sollen, auch statisch abgelegt kein Problem. Bspw. die von dir genannten MwSt. Sätze oder ähnliches, was unveränderlich ist und nur gelesen wird. Daher wird Request 1 auch nicht hingehen und den Wert ändern oder in einer Form nutzen, die dann bei Request 2 für Probleme sorgt.
Ganz anders sieht das aber bspw. bei Datenbanken aus. Wenn Du bspw. eine SqlConnection, ein SqlCommand, ... als statische Eigenschaft ablegst und diese dann von überall aus verwendest (das ist meiner Erfahrung nach auch das häufigste Beispiel für diese Art von Fehler, da man sich dann das Instanzieren und Öffnen der DB Verbindung an x verschiedenen Stellen "spart"), kannst Du der Webanwendung eigentlich gleich Lebwohl sagen, denn wenn die auch nur einigermaßen frequentiert ist, kommt es zu immensen Problemen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Ich gebe Stefan absolut recht und arbeite bei einer Webanwendung immer nur requestabzogen. Statische Methoden nutze ich bei Webanwendungen auch statische Eigenschaften aber nie.
Man darf eine Webanwendung nicht mit einer Desktopanwendung vergleichen, das sind 2 grundlegend verschiedene Welten mit eigenen regeln.
Gruß Thomas
Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!
Dev Apps von mir: Icon für UWP, UI Strings
Andere Dev Apps: UWP Community Toolkit Sample App -
Hi Atlan,
wenn die Windows-Anwendung stabil laufen würde, dann würde ich vor dem gesamten Umbau die Datenzugriffsschicht mit dem Cache als Singleton in der Web-Anwendung laufen lassen. Es müssten dann lediglich die Methoden dieser Singleton-Instanz threadsicher sein, ggf. erst einmal nur mit synclock Da würden zwar die Response-Zeiten nicht optimal sein, aber es sollte erst einmal stabil laufen.
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und TricksHallo Peter,
solche Überlegungen hatte ich am Anfang auch, aber so ganz stabil ist die Anwendung eben leider doch nicht. Sie ist eben auf den Einzelplatzbetrieb ausgelegt. Näheres weiter unten, in der Antwort zum Caching...
Gruß, Karsten
-
Hallo,
eine interessante Diskussion ;-)
Das Elemente "requestbezogen" ermittelt werden, hatte ich glaube ich nicht in Frage gestellt und erscheint mir ziemlich trivial. Trotzdem handelt es sich ja wohl um eine Anwendung und nicht mehrere Anwendungen. Das Daten zwischen "Requests" oder "Threads" vermittelt werden, ist in meinem Alltag jedenfalls keine Rarität. Ich denke da auch interaktive Webanwendungen, im einfachsten Fall eine Chat-Anwendung.
Und eine SQL-Connection sollte natürlich auch nicht "geteilt" werden (das kann man wissen), aber das sollte nicht zu der allgemeinen Empfehlung führen, in allen Kontexten keine static Variablen nutzen zu sollen. Das wäre für mich eine unzulässige Einengung.
Ich glaube unverändert, die Verwendung statischer Elemente ist im Kontext bestimmter Aufgaben unvermeidlich und sehr sinnvoll. Man muss es halt richtig machen. Ansonsten sehe ich wenig (zutreffenden) Widerspruch.
Gruß
-
aber das sollte nicht zu der allgemeinen Empfehlung führen, in allen Kontexten keine static Variablen nutzen zu sollen. Das wäre für mich eine unzulässige Einengung.
Hat ja auch keiner gesagt. Die Erfahrung der letzten 15, 16 Jahre und die Probleme, die ich in meiner täglichen Communityarbeit bei den Leuten mitbekommen habe, führen aber dazu, dass ich erstmal davor warne, statische Elemente, insbesondere Eigenschaften und Variablen, zu verwenden, da insbesondere Anfänger meist gar nicht wissen, was sie sich damit für Probleme einhandeln können. Daher sollen sie erstmal ganz "normal" arbeiten und später, wenn Sie eine gewisse Erfahrung haben, kommen sie von ganz alleine darauf, was man wie machen kann.
Das ist ähnlich wie beim Autofahren. Man driftet in der Fahrschule auch nicht gleich drauflos, sondern macht das, wenn der Prüfer hintendrinsitzt :) Da hat man ja schon ein paar Fahrstunden und viel Erfahrung^^
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Freitag, 15. Dezember 2017 08:11
-
Hallo zusammen,
das Problem mit dem Caching in unserer Anwendung ist leider viel tiefgreifender. Ich gebe euch insofern Recht, wenn es darum geht, allgemeine Daten wie "Mengeneinheiten", "Länder" oder "Währungen" zu cachen.
Bei uns jedoch wurde versucht, alles mögliche zu cachen. Wir reden hier von einer betriebswirtschaftlichen Anwendung, also gibt es solche Daten wie "Konten", "Kostenstellen", "Kostenträger" oder "Kontokorrentkonten". Nun hat man das System so gestaltet, dass ein Fenster, welches zum Beispiel ein Konto angezeigt hat, diese Konto aus einem Cache bezieht. Der Cache entscheidet, ob er das Konto aus der Datenbank holt oder schon hat. Das nächste Fenster kriegt dann das gleiche Objekt. Beide Fenster werden als "Besitzer" des Objektes vermerkt und müssen beim Schließen sich vom Objekt abmelden. Beim letzten Besitzer wird dann das Objekt entsorgt.
So weit, so gut. Die Theorie klingt, die Praxis hat ein paar Tücken. So ist es zum Beispiel so, dass ein Objekt als Eigenschaft auch andere Objekte hat. Diese werden dann unter dem Besitzer des Parent-Objektes nachgeladen. So hat ein "Mandant" zum Beispiel ein Konto für die Steuer. Wird der Mandant also angezeigt, wird auch das Konto mit geladen. Werden jetzt zufälligerweise Buchungen auf das Konto importiert, so hängen diese letztlich alle am Konto und damit am Mandant. So lange, wie das Mandantenfenster nicht geschlossen wird, bleiben die Daten alle im RAM. Sehr nett, wenn man zufällig mal mehrere Tausend Buchungen importieren will. Letztlich hat immer nur alles funktioniert, wenn man brav alle Fenster der Anwendung sofort wieder schließt.
Das nächste Problem ist ja die Synchronisierung der Anzeigen. Wenn zwei Fenster das Gleiche anzeigen und ein Fenster etwas ändert, so ist das andere nicht mehr aktuell. Das hat man erkannt und jede Klasse mit "PropertyChanged"-Events bestückt und jedes Fenster mit Eventhandlern versehen, damit diese Fenster eine Änderung auch mitkriegen. Die Folge waren eine Flut von unkontrolliert angebundenen Events, die teilweise nicht mehr entfernt wurden und somit verhindert hatten, dass der Garbage Collector seine Arbeit tun kann.
Und eine solche Konstruktion sollte nun per Webservice angebunden werden :-)
Ich habe tabula rasa gemacht und die relevanten Codestellen neu geschrieben. Es ging zum Glück nur um eine begrenzte Funktionalität. Das Ergebnis spricht für sich. Im Test mit 10 Threads, die gleichzeitig den Service ansprechen, hat der Service vorher (neben merkwürdigen Fehlern) locker den RAM des Rechners gefressen (ca. 6,5 GB bei 8 GB), jetzt braucht er so maximal 300 MB. Die Responsezeiten sind gemessen etwa 5mal schneller, gefühlt ist es von träge auf rasend schnell gewechselt. So kann ich gut damit leben.
Gruß, Karsten.
-
Hallo
ich gebe ihm (Stefan) ja in vielen Dingen auch recht, bis auf:
"Bei einer Webanwendung hat man es mit dem genauen Gegenteil zu tun. Teils 100e gleichzeitig eingehende Requests, die parallel verarbeitet werden müssen. Da sind statische Variablen in der Regel der GAU."
Parallele Verarbeitung bedeutet auch nicht automatisch, dass auf gemeinsame Ressourcen zugegriffen werden muss. Es wäre aber denkbar und es muss dabei nicht automatisch ein Datenzugriff via SQL-Server sein.
Aufgrund der allgemeinen Natur der Fragestellung konnte ich aber auch nur allgemeine Dinge zum Besten geben. Hoffe, dass hat jetzt nicht zur Verwirrung geführt.
Gruß
-
Hi,
Parallele Verarbeitung bedeutet auch nicht automatisch, dass auf gemeinsame Ressourcen zugegriffen werden muss.
ich hab nicht so ganz verstanden, was Du da mit dem Verweis auf meinen Hinweis meinst. Natürlich muss nicht auf gemeinsame Ressourcen zugegriffen werden. Aber wenn man von statischen Variablen (also veränderbaren Werten/Objekten) spricht und um die geht es in der Diskussion, denke ich, dass klar ist, dass es um den Zugriff auf eben diese globalen Ressourcen geht".
Aber seis drum. Ich für meinen Teil, es ist eigentlich alles geklärt. Einsetzbar sind statische Objekte nur sehr mit Vorsicht zu genießen und man sollte genau wissen, was man sich damit antut.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
"Bei einer Webanwendung hat man es mit dem genauen Gegenteil zu tun. Teils 100e gleichzeitig eingehende Requests, die parallel verarbeitet werden müssen. Da sind statische Variablen in der Regel der GAU."
Grade dies sollte man nicht anprangern. Stefan schreibt ja auch "in der Regel" nicht immer.
Ich würde jedem empfehlen in der ersten Produktiven Version der Webanwendung komplett auf statische Variablen und Caching zu verzichten. Außer man weiß was man tut.
Erst im zweiten schritt würde ich schauen ob die Webanwendung so genutzt wird wie ich mir das vorgestellt habe und wo mit welchen mitteln ein Caching sinn macht
Gruß Thomas
Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!
Dev Apps von mir: Icon für UWP, UI Strings
Andere Dev Apps: UWP Community Toolkit Sample App -
Hallo Thomas (und auch alle anderen Mitleser),
bzgl. Caching evtl. noch der Hinweis: Es gibt keinen Grund, für Caching eigene statische Eigenschaften zu nutzen. Hierfür gibt es spezielle Cache Objekte in ASP.NET (auch Core).
Bspw. über HttpContect.Current.Cache oder HttpRuntime.Cache, ... anzusprechen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Freitag, 15. Dezember 2017 13:49
-
Danke für den Hinweis Stefan. Kannte ich bisher noch nicht. Ich erzeuge aber ehr ein Client seitigen Cache zudem cache auch ja der SQL Server was für meine Anwendungen bisher immer ausreichend war.
Gruß Thomas
Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!
Dev Apps von mir: Icon für UWP, UI Strings
Andere Dev Apps: UWP Community Toolkit Sample App