Hallo Palladin007,
ich hab in meiner Antwort unten auf deine Punkte / Frage reagiert, fürchte aber dass wir so nicht weiterkommen.
Daher beschreib bitte den zeitlichen Ablauf wann was passieren soll. Zuerst einmal für einen Benutzer.
Dann wie es für mehrere Benutzer ausschaut.
Berücksichtige dabei bitte auch, dass wir keine Ahnung von deinem Projekt haben (du jedoch hoffentlich schon 😉).
Alle ThreadPool-Threads wollen synchron auf je einen Task warten, diese Tasks bekommen aber keinen Platz auf dem ThreadPool, weil jeder ThreadPool-Thread auf "seinen" Task wartet.
Auch unter .NET 4.x funktioniert so der ThreadPool nicht. Wenn der TP merkt dass "zuwenig weitergeht", so werden mehr Threads injiziert.
Wenn die Annahme von max. 8000 gilt, so wären das max. 8000 Threads und das ist bei einer CPU mit wesentlich weniger Kernen wohl nicht zielführend (der arme OS-Scheduler soll ja schauen dass die Arbeiten auf die CPUs möglichst fair verteilt werden).
entweder mit Task.Factory.StartNew() und TaskScheduler.Default oder Thread.UnsafeQueueUserWorkItem().
Zwischenfrage: Gibt es da relevante Unterschiede zwischen beiden, wenn das Ziel nur ist, keinerlei Context-Informationen durchreichen zu lassen?
Bei ersterem hast du halt einen Task, bei letzterem nicht.
D.h. Status, Fehlerbehandlung ist mit dem Task meist einfacher. Ebenso falls Continuations benötigt werden hat der Task seine Vorteile und wurde ursprünglich genau wegen solcher Dinge auch eingeführt.
Meine ursorüngliche Aussage, dass sie auf ein Datum warten, war falsch.
Ich können es tatsächlich nicht konkret sagen, wir haben leider auch kein brauchbares Logging, was etwas darüber verraten könnte.
Aber in der Regel sieht es so aus, dass ab einem Datum ein Prozess aus Sicht des Nutzers frei gegeben wird und dann können die Nutzer los legen
Da bin ich bisher noch nicht mit Infos gesegnet 😉
Weiter oben steht
Es wird kein Ergebnis errechnet, sondern eine externe Komponente gesteuert und überwacht.
Was nun?
Wird eine Komponenten überwacht und wenn Ereignis X eintritt, so gehts los?
Oder ist mit Datum wirklich ein Zeitpunkt gemeint, andem ein Benutzer los legen kann?
Warum dann der Request bereits vorher und dieser soll auf das Datum warten?
und sie haben ein Zeitfenster von 2 Monaten
Was passiert in diesem Zeitfenster, v.a. in Hinsicht auf die eingangs (OT) Requests?
Mir fehlt, auch jetzt noch, eine Beschreibung was das Ziel der Sache sein soll.
Wie lange dauern die Requests i.d.R., usw.
Es gibt jede Menge an Sequentialisierung-, Skalarsierung-, etc. Code, aber um das passende Verfahren auszuloten, sollte bekannt was erwünscht ist.
Das funktioniert leider auch nicht, weil die Requests die Antwort oder ggf. Fehler-Informationen selber sofort brauchen.
Das Problem gibt es so gut wie immer. Wobei auf was bezieht sich "sofort"?
Wenn die Request u.U. lange warten, dann ist "sofort" auch schon wieder später.
Warum ist ein "Ablegen" der Anfrage via HTTP, Bearbeitung und dann asynchrone (hier nur zeitlich gemeint) Rückmeldung via SignalR nicht möglich? Das kann sogar eher "sofort" durchgeführt werden, da das System insgesamt weniger unter Last steht und nicht >> Threads benötigt werden.
Aufsplitten, dass das Frontend erst später informiert wird, kommt leider auch nicht in Frage.
Warum nicht? Das wäre gängige Praxis und lässt sich auch mit ASP.NET (nicht Core) umsetzen.
Eine Annahme von mir für ein potentielles Deadlock-Risiko war ja, dass alle ThreadPool-Threads beschäftigt sind, indem sie Tasks auf den ThreadPool ausführen wollen.
Ein guter TP fügt dann einfach mehr Threads hinzu -- und entfernt diese ev. später wieder wenn sie nicht mehr benötigt werden.
Das Verhalten vom Windows-ThreadPool kenn ich aber nicht, nur jenes vom .NET ThreadPool.
Ein Deadlock ist da eher unwahrscheinchlich, eher Thread-Starvation od. Thread-Exhaustion, also dass die CPU vor lauter Threads kaum mehr wirklichen Fortschritt macht od. dass eben keine Threads mehr verfügbar sind.
Daher auch meine Intention zu erfahren was passiert, damit mit möglichst wenigen Threads das gelöst werden kann.
Meinst Du damit die Tatsache, dass die Requests alle synchron arbeiten und damit über die ganze Laufzeit diesen einen Thread blockieren, obwohl eigentlich 99% der Zeit nur auf IO gewartet werden muss?
Wenn auf IO sync gewartet wird, so ist dieser Thread eben blockiert bis IO fertig ist.
Auf IO kann jedoch async gewartet werden, dann wird kein Thread blockiert. Erst wenn IO fertig ist, so wird über den sog. IO-Completionport (ein Windows-Konzept, das es z.B. in Linux so nicht gibt / nicht verbreitet ist) einem im IO-ThreadPool verfügbaren Thread signalisiert dass er mit der "Continuation" (also ab nun dem folgenden Benutzercode) fortfahren kann.
Sind hier jedoch sehr viele (max. 8000?) Continuations registriert, so gibt es eine Menge zu tun. Da bin ich mir sicher, dass diese anders gelöst werden kann.
Oder meinst Du, dass ich den CustomTaskScheduler mit nur einem Thread implementiert habe?
Ich hab mir den Code (mangels Zeit) nicht angeschaut.
mfG Gü