1

In einer Asp.NET MVC-Anwendung habe ich ein Projekt mit einem Diagramm der Aktivitäten zu verfolgen.Parallele CPU-intensive Vorgänge in ASP.NET

Ein Projekt hat keinen einzigen Stamm, sondern mehrere. Jeder Baum kann komplex und tiefgründig sein und jeder Knoten hängt von den anderen ab, etwa von Daten und detaillierten Benutzerberechtigungen.

Ich muss das gesamte Projekt Graph jedes Mal, wenn ich eine Operation auf einem Knoten tun, weil sogar verschiedene Zweige voneinander abhängig ist.

Die Struktur wird flach in einem SqlServer DB gespeichert.

Um den Baum zu erstellen, habe ich eine rekursive Funktion, die viele Dinge tun, um einige Daten für jeden Knoten (im Kontext des aktuellen Benutzers) zu erstellen.

Zum Beispiel habe ich ein Projekt mit 3000 Knoten, die mehr als 2 Sekunden dauert, um mit einem einzigen Aufruf zu verarbeiten, die den gesamten Graphen erstellen.

public static List<Nodes> GetProject(...) { 
    var list = new List<Nodes>; 
    CreateTreeRecursive(...); 
    return list; 
} 

Denken Sie daran, dass ich mehrere Wurzeln habe. Dadurch kann ich die Arbeit parallelisieren und jeden Zweig unabhängig voneinander bearbeiten.

Wenn ich parallel die Ausführung mit Task.Run oder Parallel.ForEach die Zeit, um den gesamten Graphen zu erstellen, ist im Bereich zwischen 15 und 50 ms, 50-mal schneller.

public static List<Nodes> GetProject2(...) { 

    var list = new List<Nodes>; 

    Parallel.ForEach(..., 
    (root) => { 
     ... 
    }); 

    return list; 
} 

Die schlechte Nachricht ist, dass Sie keine Threads in ASP.NET erstellen sollten.

Im konkreten Fall habe ich nicht viele gleichzeitige Benutzer, aber mit einer Zielgruppe von ~ 200 Benutzern können Sie nicht wirklich sicher wissen.

Die andere Sache ist, dass die Wurzeln in einem Projekt können viele, bis zu 100, so viele Threads würden erstellt werden.

Diese Lösung wäre so einfach, aber nicht anwendbar.

Gibt es eine Möglichkeit, dies in einer einfachen Art und Weise zu tun oder meine einzige Option ist die Arbeit zu einem externen Dienst zu entladen, der mehrere Threads umfassen kann und asynchron wartet?

Wenn dies der Fall ist, würde ich mich über einige Vorschläge freuen?

Um klar zu sein, ist dies eine Operation, die für jede Benutzerinteraktion im Projekt durchgeführt wird. Ich kann das Ergebnis nicht zwischenspeichern, ist zu volatil. Ich kann mich nicht in die Warteschlange einreihen und schließlich das Ergebnis bekommen.

Dank

+0

Normalerweise werden solche Probleme durch Caching behandelt, ist das mit Ihrer Datenquelle machbar? Sie sind möglicherweise nicht in der Lage, eine gesamte Struktur zwischenzuspeichern, aber Untergruppen der Struktur können möglicherweise cache-fähig sein und müssen nicht neu berechnet werden. –

+0

Müssen die Benutzer den Status von 3000 einzelnen Knoten wirklich kennen? Wenn sie verschiedene Zweige sind und voneinander abhängig sind, haben sie nicht das Gefühl, dass sie für mich andere Zweige sind. Auf der Grundlage dessen, was Sie sagen, ist es für uns unmöglich, Ihr Problem zu lösen, und bestenfalls können wir einen allgemeinen allgemeinen Rat geben, der für die Lösung von Problemen nicht wirklich nützlich ist, weil wir nicht wissen, was Sie wissen. –

+0

@ScottChamberlain Ja, ich könnte die Zweige zwischenspeichern, aber wenn die Änderungen häufig sind, riskiere ich sehr kurze lebende Cache-Einträge. Jedes kleinste geänderte Datenstück bedeutet eine Ungültigkeitserklärung der Verzweigung. – sevenmy

Antwort

1

Die schlechte Nachricht ist, dass Sie keine Threads in ASP.NET erstellen soll.

Dies ist nicht wahr und diese falsche Annahme blockiert die richtige Lösung.

Sie können Threads erstellen. Das Risiko, das Sie wahrscheinlich haben, ist, dass Sie die Kapazität des Thread-Pools erschöpfen könnten. Dies ist im Allgemeinen nicht leicht zu machen.

Ihre Threads sind CPU-gebunden. Dies bedeutet, dass Ihr Server vollständig überlastet ist, lange bevor der Pool erschöpft ist. Die Poolkapazität ist nicht Ihr limitierender Faktor.

Mit einigen Annahmen können wir uns ein konkretes Szenario ausdenken: Ein 8-Core-Server ist mit 8 Threads gesättigt (die wie hier runnbar sind). Der Thread-Pool wird jedoch nicht als überladen betrachtet, wenn weniger als 100 Threads vorhanden sind. (Die tatsächliche Anzahl variiert. 100 sollte in einem breiten Bereich von Fällen sicher sein.)

Ferner verwendet Parallel.ForEach Pool-Threads. Es erstellt keine sinnvolle Menge an Threads. Es belegt auch nicht einen Thread pro Eingabeelement.

Ich sehe nichts, worüber ich mir Sorgen machen müsste.

+0

Das wäre fantastisch. Wenn ich also 100 Zweige habe, erzeugt Parallel.ForEach keine 100 Threads? Und Aufgabe.Run? Und wie wirkt sich die Anzahl der gleichzeitigen Benutzer aus? – sevenmy

+0

Für die ersten beiden Fragen sollten Sie das nachforschen. Viel mehr als das, was ich hier hinzufügen kann, wurde dokumentiert. Bei gleichzeitigen Benutzern ist diese Metrik bedeutungslos. Lassen Sie uns über gleichzeitige Anfragen sprechen. Ich sehe nicht, warum Parallelismus hier eine Auswirkung hätte, wenn man davon ausgeht, dass Ihr Server nicht überlastet ist. Wenn Sie es überladen, sind alle Wetten ausgeschaltet, aber das ist, denke ich, intuitiv klar. – usr

+0

Da Ihre Berechnung nach 50 ms erfolgt, besteht kein Risiko, andere Benutzer zu verdrängen. – usr