Wie zu verwenden Threadpool.QueueUserWorkItem in einem windows-Dienst?
Ich habe einen windows-Dienst, wo ich mit Threadpool.QueueUserWorkItem. Der service verbindet, um mehrere client-Datenbanken, packt die Daten, konvertiert Sie in die Formate XLS und senden von Dateien an den entsprechenden FTP.
Ich habe 3 Fragen bezüglich des Kodex unter:
- Bin ich mit dem Threadpool.QueueUserWorkItem richtig?
- Brauche ich Schloss irgendwo in den code, um Probleme zu vermeiden? Wenn ja, wo und zu welchem Zweck.
- Gibt es etwas, das nicht korrekt in den code? Wenn ja, was und wie mit Ihr umgehen?
Code:
private static System.Timers.Timer aTimer = new System.Timers.Timer(50000);
public void OnStart(string[] args)
{
CLE.WriteToEventLog("Service Started");
try
{
aTimer.Elapsed += new ElapsedEventHandler(PerformTimerOperation);
aTimer.Enabled = true;
}
catch (Exception ex)
{
CLE.WriteToEventLog("Error Starting Service: " + ex.Message);
}
}
private void PerformTimerOperation(object source, ElapsedEventArgs e)
{
CLE.WriteToEventLog("Timer Operation Started");
Clients objClient = new Clients();
List<Clients> objClientList = Clients.GetClientList();
foreach (var list in objClientList)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(SendFilesToClient), list);
}
}
private void SendFilesToClient(Object stateInfo)
{
CLE.WriteToEventLog("Send Files To Client Started");
Clients oClient = (Clients)stateInfo;
CLE.WriteToEventLog("Start Proecessing Client: " + oClient.ClientName + ", ClientId: " + oClient.ClientId);
connectionString = App.Database.PrimaryConnectionString(oClient.ClientId);
string reports = oClient.Reports;
string[] values = reports.Split(',').Select(sValue => sValue.Trim()).ToArray();
foreach (string item in values)
{
//Send data to FTP based on cliend id
}
//At this point all reports are being sent to the FTP. We will update the database with LastExecutionDateTime + 1 hour. This will be used as DateFrom param for all reports for the next execution.
}
Der service funktioniert einwandfrei und ich bekomme die entsprechenden Ergebnisse, aber ich brauche zu machen sicher, ich mache es richtig und nicht in die Fragen später.
- Nur hat das @Grau. Es ist C# .NET 4.0
- Das sieht fein zu mich. Bezüglich Ihrer Frage #2, sollte es keine Notwendigkeit für sperren, da Ihre threads laufen völlig unabhängig voneinander. Die Schleusen sind notwendig, wenn Sie die Koordinierung des Zugriffs auf eine gemeinsame Ressource, aber in diesem Fall ist jeder worker-thread hat seine eigene Datenbank und arbeitet auf einem Satz von "Zeug".
- Danke @GalacticCowboy!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich bin vorausgesetzt, Ihr service soll weiter laufen im Gegensatz zu "one-and-done". Wenn dem so ist, bitte beachten Sie, dass die
AutoReset
Eigenschaft desSystem.Timers.Timer
Klasse ist auftrue
standardmäßig. Dies bedeutet einfach, dass der timer weiter zu erhöhen, dieElapsed
Ereignis jedes mal die 50-Sekunden-Intervall verstreicht (50000 Millisekunden = 50 Sekunden). Wenn Sie wissen, sicher, dass alleSendFilesToClient
Vorgänge rechtzeitig vor dem nächsten Intervall verstreicht, dann sollten Sie ok sein. Allerdings würde ich nicht darauf Wetten. Was ist, wenn sich die Datenbank auf dem Netzwerk und das Netzwerk ausfällt? Was ist, wenn der Dienst ausgeführt wird, auf einem langsameren system oder eins mit weniger Kernen und all die Arbeit ist nicht abgeschlossen in der Zeit?Sie könnten dies umgehen, indem Sie das
AutoReset
feature so gerne.Dies bedeutet, dass die
Elapsed
- Ereignis wird nur ausgelöst, sobald. Innerhalb derPerformTimerOperation
einfach rücksetzen derEnabled
Eigenschafttrue
den timer neu starten, bevor Sie verschwinden.Aber dies ist eine unvollständige Lösung, da die Gewinde immer noch zu lange dauern, um abzuschließen, bevor der timer löst
Elapsed
Veranstaltung. In diesem Fall möchten Sie vielleicht die Verwendung einerManualResetEvent
zu signalisieren, wenn jeder thread abgeschlossen ist, und unterbrechen beendenPerformTimerOperation
(und der timer zurückgesetzt), bis das Auftritt. Zum Beispiel,Nun update
SendFilesToClient
.In diesem Mode, der
PerformTimerOperation
wird der block auf dieWaitHandle.WaitAll()
aufrufen, bis alle worker-threads, z.B.SendFilesToClient
, signalisieren, dass Sie fertig sind. An diesem Punkt, Sie die Stoppuhr zurücksetzen und wiederholen Sie den Vorgang mit dem nächsten Intervall.Sorry das ist so lange. Hoffe, es hilft.
PerformTimerOperation
dauert normalerweise nicht länger als ein paar Minuten, ich vermute, du bist ok.