Come elaborare gli elementi in coda in serie su un thread a bassa priorità usando estensioni parallele
-
27-09-2019 - |
Domanda
Voglio sapere qual è il modo migliore per elaborare i risultati di un processo a lungo in esecuzione in serie, ma su un thread a bassa priorità utilizzando il . NET 4.0 le estensioni parallele .
Ho il seguente classe che sia fa l'esecuzione e fornisce i risultati:
public class Step
{
public string Name { get; set; }
public TimeSpan Duration { get; set; }
public bool Completed { get; set; }
public void Execute()
{
DateTime before = DateTime.Now;
RemotedService.DoSomeStuff();
Duration = DateTime.Now - before;
Completed = true;
}
}
Come posso elaborare questi passi e anche salvarli in un file, in ordine, dopo che sono stati elaborati? Vorrei salvarli in un file mentre RemotedService.DoSomeStuff()
è in attesa di una risposta dal server.
La scrittura il file sarebbe come questo:
using (StreamWriter w = File.AppendText("myFile.txt"))
{
var completedStep = completedSteps.Dequeue();
w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}",
completedStep.Name,
completedStep.Completed,
completedStep.Duration));
}
Una possibilità che viene in mente è quello di aggiungere a un Queue
e hanno un Timer
che i processi di loro. Ma questo non sfruttare i tempi morti delle chiamate comandate a distanza.
Un'altra opzione che viene in mente è quello di scrivere in modo asincrono ogni risultato per il file utilizzando un System.Threading.Tasks.Task
per Step
, ma che non garantisce che verranno salvati in ordine e possono anche introdurre contesa con la scrittura al file.
Soluzione
Vorrei suggerire la creazione di un BlockingCollection<Step>
(vedi System.Collections.Concurrent
namespace). Come ogni fase è stata completata, è sommato a quello di raccolta. Il comportamento predefinito di BlockingCollection
è quello di funzionare come una coda, in modo otterrete il comportamento FIFO che stai cercando.
Un secondo filo servizi della coda, la rimozione di ogni elemento e la scrittura in un file di log.
Quindi, se si aggiunge la coda:
static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>();
Si dovrebbe aggiungere questo al tuo metodo di Execute
, dopo che l'oggetto è stato completato:
LogQueue.Add(this);
E il tuo thread di registrazione, che si dovrebbe iniziare nel costruttore statico:
static void LoggingThread()
{
using (var w = new StreamWriter(...))
{
while (!LogQueue.IsCompleted())
{
Step item;
if (LogQueue.TryTake(out item))
{
w.WriteLine(....);
}
}
}
}
Il filo di registrazione, come ho scritto che utilizza un filo System.Threading
. Ci potrebbe essere un modo più semplice, o meglio farlo con TPL. Non ne sono ancora terribilmente familiarità con TPL, quindi non ho potuto dire.
Altri suggerimenti
Un approccio è quello di creare un costume Utilità di pianificazione (vedi http: // msdn .microsoft.com / en-us / library / ee789351.aspx ). La vostra abitudine task scheduler può limitare la concorrenza a one-at-a-tempo e far rispettare rigorosa esecuzione in-order.
La creazione di un programmatore di operazione permette anche di controllare la priorità del thread, o l'ApartmentState che può essere desiderabile in alcune situazioni.
Si sta letteralmente descrivendo il caso d'uso per il Workflow Foundation - Lo fa tutte queste cose per voi:)