Laden...

Unendliche Parrallel Foreach schleife?

Erstellt von Pain vor 9 Jahren Letzter Beitrag vor 9 Jahren 3.945 Views
P
Pain Themenstarter:in
34 Beiträge seit 2008
vor 9 Jahren
Unendliche Parrallel Foreach schleife?

Hallo Ihr,
ich habe folgendes Problem. Ich habe eine Liste von Dateien die parrallel unendlich lange ausgeführt werden sollen.

quasi folgendes:

Parallel.ForEach(Files, file =>
            {
                while (true)
                {
                   // do stuff
                }
            });

leider bin ich mir dabei ziemlich sicher, dass dann das Threading nicht mehr richtig funktioniert, da der Thread ja dauerhaft in der while schleife hängt.

Was meint ihr? Gibt es alternativen? Für mich wäre eine alternative die Logik eine eigene Executable auszulagern und diese dann 250x mal zu starten, und diese beinhalten dann eine while(true) schleife . Ich hätte es aber eigl. lieber in einer Applikation.

16.807 Beiträge seit 2008
vor 9 Jahren

Sowas deckt man mit einen Producer/Consumer Pattern ab; eventuell je nach Anforderung direkt eine Pipeline.
Siehe auch TPL Pipelines

T
2.219 Beiträge seit 2008
vor 9 Jahren

Meine erste Frage ist eher was du mit diesen Endlos Schleifen erreichen willst 😃
Sinnvoll klingt dies ohne weitere Informationen eher nicht.
Willst du Dateien verarbeiten oder nur beobachten?

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

P
Pain Themenstarter:in
34 Beiträge seit 2008
vor 9 Jahren

verarbeiten, und das muss dauerhaft passieren. Was wäre mit:

 Parallel.ForEach(Files, file =>
            {
                Thread t = new Thread(() =>
                {
                    // do stuff
                        Thread.Sleep(2);
                    }
                });
                t.Start();
            });

ich habe herausgefunden, dass das deutlich besser / schneller funktioniert?

16.807 Beiträge seit 2008
vor 9 Jahren

Ich könnte mich ja selbst zitieren....oder Du liest einfach den Link.
Das behandelt genau das Thema - und den passenden Pattern hab ich ebenfalls genannt......

Lass die Finger von dem Parallel-Konstrukt weg. Auf Deutsch gesagt ist das Müll.

2.207 Beiträge seit 2011
vor 9 Jahren

verarbeiten, und das muss dauerhaft passieren.

Das ist kein Grund, warum das mit Abts Link nicht gehen sollte. Es gibt keinen Grund eine Parallel-Foreach-Endlossschleife zu machen.

Gruss

Coffeebean

W
955 Beiträge seit 2010
vor 9 Jahren

... wobei dann natürlich TPL Dataflow noch einfacher ist.

1.361 Beiträge seit 2007
vor 9 Jahren

bezüglich TPL Dataflow: Stackoverflow: Proper way to implement a never ending task

beste Grüße
zommi

P
Pain Themenstarter:in
34 Beiträge seit 2008
vor 9 Jahren

danke für die Antworten, ich hatte heute ein wenig Zeit mir das TPL Dataflow Pattern anzugucken. Ich habe jedoch noch einige Verständnis Probleme. Ich habe das Pattern aus dem Stackoverflow Forum übernommen jedoch verstehe ich noch nicht genau wie das Pattern angewendet wird zb in meinem Fall

static void StartWork(string fileUrl)
        {
            // Create the token source.
            wtoken = new CancellationTokenSource();

            // Set the task.
            task = (ActionBlock<DateTimeOffset>)CreateNeverEndingTask(now => CheckFile(fileUrl), wtoken.Token);

            // Start the task.  Post the time.
            task.Post(DateTimeOffset.Now);
        }

und dann für jedes file die Methode "StartWork" aufrufen? Meiner Meinung nach kann das nicht richtig sein, da "task" kein Array ist sondern nur eine einzelne variable und daher kein array verarbeiten kann? Ich habe noch etwas Probleme zu Verstehen in wie fern mir das Helfen soll. Ich habe verstanden, dass es über die Action Blöcke es besser ist "unendlich" Schleifen zu erstellen, jedoch bin ich mir nicht sicher ob ich einfach alle meine Aktionen(für alle files) an den task "posten" soll oder ob ich für jedes file ein neuen task benötige. Die files sollen nach Möglichkeit auch alle parrallel verarbeitet werden.

Gruß & Danke!

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Pain,

Die files sollen nach Möglichkeit auch alle parrallel verarbeitet werden.

die optimale Anzahl der (echt) parallele Aufgaben hängt mehr von den Architektur des Rechners und seiner Ressourcen (Anzahl Cores, Anzahl IO-Kanäle usw.) ab und natürlich von der Art der Aufgaben, aber weniger von der Größe der Eingabemenge. Der Versuch, auf Biegen und Brechen alles anstehenden Eingaben parallel zu bearbeiten, kann und wird die Gesamtlaufzeit eher verlängern.

Wenn die Aufgaben CPU-lastig sind, liegt die optimale Anzahl typsicherweise bei oder in der Nähe der Anzahl der vorhanden Cores.

Das parallele Einlesen von mehreren (großen) Dateien von einer einzelnen mechanischen Festplatte ist dagegen meistens eher kontraproduktiv, siehe Multithreaded File I/O, insbesondere die Diagramme auf der zweiten Seite.

Aus meiner Sicht macht es Sinn, die optimale Anzahl von Workern zu ermitteln/abzuschätzen, dann diese Anzahl an Worker zu erstellen bzw. zu verwenden. Die Aufgaben werden dann in eine zentrale Queue gestellt, aus der sich jeder Worker/Consumer in einer (quasi) Endlosschleife die jeweils nächste Aufgabe herausholt und bearbeitet.

herbivore

P
Pain Themenstarter:in
34 Beiträge seit 2008
vor 9 Jahren

Danke herbivore. Noch ein Frage, werden die "tasks" die via " task.Post(DateTimeOffset.Now);" "gepostet" werden Parallel verarbeitet oder sequentiell?
Edit: Sequentiell...

Ich weiß nicht wie mir das TPL Pattern bei meiner Herausforderung helfen soll. Da ich zwar eine "Endlosschleife" Hinbekommen habe, diese jedoch nicht parralel ausgeführt wird. Ich habe jetzt folgendes angedacht:

string[] files= new string[] { "test", "test1", "test2" };
            Parallel.ForEach(files, file =>
            {
                StartWork(file);
            });


static void StartWork(string fileUrl)
        {
            // Create the token source.
            wtoken = new CancellationTokenSource();

            // Set the task.
            task = (ActionBlock<String>)CreateNeverEndingTask(now => DoWork(now), wtoken.Token);

            // Start the task.  Post the time.
            task.Post(fileUrl);
        }

Aber ob diese Lösung viel besser ist als


Parallel.ForEach(Files, file =>
            {
                Thread t = new Thread(() =>
                {
                    // do stuff
                        Thread.Sleep(2);
                    }
                });
                t.Start();
            });

????

16.807 Beiträge seit 2008
vor 9 Jahren

Natürlich ist die viel besser... warum reden wir uns denn den Mund fusselig...
Ich denke Dir fehlen auch die Basics Thread vs. Task....

P
Pain Themenstarter:in
34 Beiträge seit 2008
vor 9 Jahren

Danke, ich habe die Aufrufe als asynchron deklariert, damit scheint mein vorhaben auch ohne Parralel.Foreach zu funktionieren:


ITargetBlock<Account> CreateNeverEndingTask(Func<String>, CancellationToken, Task> action, CancellationToken cancellationToken)
        {
            // Validate parameters.
            if (action == null) throw new ArgumentNullException("action");

            // Declare the block variable, it needs to be captured.
            ActionBlock<String> block = null;

            // Create the block, it will call itself, so
            // you need to separate the declaration and
            // the assignment.
            // Async so you can wait easily when the
            // delay comes.
            block = new ActionBlock<String>(async now =>
            {
                // Perform the action.  Wait on the result.
                await action(now, cancellationToken).
                    // Doing this here because synchronization context more than
                    // likely *doesn't* need to be captured for the continuation
                    // here.  As a matter of fact, that would be downright
                    // dangerous.
                    ConfigureAwait(false);

                // Wait.
                await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken).ConfigureAwait(false);
                // Same as above.


                // Post the action back to the block.
                block.Post(now);
            }, new ExecutionDataflowBlockOptions
            {
                CancellationToken = cancellationToken
            });

            // Return the block.
            return block;
        }

Welche Variante ist nun besser?