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.
Sowas deckt man mit einen Producer/Consumer Pattern ab; eventuell je nach Anforderung direkt eine Pipeline.
Siehe auch TPL Pipelines
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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.
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?
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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
bezüglich TPL Dataflow: Stackoverflow: Proper way to implement a never ending task
beste Grüße
zommi
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!
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
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();
});
????
Natürlich ist die viel besser... warum reden wir uns denn den Mund fusselig...
Ich denke Dir fehlen auch die Basics Thread vs. Task....
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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?