2016-03-22 9 views
0

Diese Frage besteht aus zwei Teilen. Ich habe eine Konsolenanwendung, die Informationen von mehreren Servern erhält und diese Informationen in einer Datenbank speichert. Um zu erreichen, dass dies simultan ausgeführt wird, habe ich Threads verwendet. Ich versuche diese Ausführung jede Minute automatisch auszuführen.Wie man Threads jede Minute richtig ausführt?

Suche Stackoverflow ich, dass dies funktioniert könnte:

var timer = new System.Threading.Timer((e) => 
     { 
      var models = ServerHandler.GetServerModels(); 

      foreach (var m in models) 
      { 
       ServerHandler.MakeThreads(m); 
      } 

      Console.WriteLine("Running..."); 
      Console.WriteLine("Press 'X' to exit or close the window, i : " + i); 

      i++; 


     }, null, 0, TimeSpan.FromMinutes(1).Seconds); 

Dies ist jedoch nicht wie erwartet funktioniert, führt er nur einmal. Wenn ich zum Beispiel ändern diese:

TimeSpan.FromMinutes(0.5).Seconds 

Oder:

TimeSpan.FromSeconds(30).Seconds 

Dann funktioniert es. Was mache ich falsch?

zweiten Teil dieser Frage:

Wenn dies tatsächlich funktioniert, wie ich oben etwas anderes zeigte passiert. Der Prozess läuft kontinuierlich und nach 474 Threads stürzt er ab und sagt, dass das System nicht genügend Arbeitsspeicher hat.

Ich versuchte mit Thread-Schlaf für diese, aber wenn ich das tue, hört es auf auszuführen, nachdem es einmal runed hat.

dies Einschließlich wenn es helfen könnten:

public static void MakeThreads(ServerModel model) 
{ 
    Thread thread = new Thread(() => SaveServerInfo(model)); 
    thread.Start(); 
    //Thread.Sleep(1); 
    //thread.Join(); 

} 

Wie kann ich diese Arbeit machen?

+2

'TimeSpan.FromMinutes (1) .Seconds' 0 zurück Sie wollen 'TimeSpan.FromMinutes (1) .TotalSeconds', die 60. –

+0

I zurück würde die Überladung "TimeSpan" verwenden. _https: //msdn.microsoft.com/en-us/library/ah1h85ch (v = vs.110) .aspx_ –

+0

Wie wäre es mit 'TimeSpan.FromSeconds (60) .Seconds'?! –

Antwort

2

In Ihrem ersten Problem mit den .Seconds wird nur den Sekundenwert zurückgeben, aber Sie definieren den Minutenwert als .5, so dass Sekunden immer Null sind.

Wenn Sie die Sekunden Sie Gesamt

TimeSpan.FromMinutes(0.5).TotalSeconds 

und im Zeitraum verwenden müssen zurückkehren möchten Sie verwenden Sie sollen die Millisekunden definieren. Sie erhalten also eine große Anzahl von Threads, da sie alle 30 Millisekunden anstatt alle 30000 Millisekunden ausgeführt werden.

So verwenden

TimeSpan.FromMinutes(0.5).TotalMilliseconds 

oder was ich immer einfacher finden

(int)(1000 * 60 * 0.5) // Then you just replace the 0.5 with the number of seconds. 
+0

versucht, dass es jede Sekunde läuft, bis ich 475 Threads habe und dann stürzt – ThunD3eR

+0

ab, also dauert die Ausführung länger als das Intervall. Das ist ein Leistungsproblem. Sie sollten etwas anderes versuchen ... –

+0

@ Ra3IDeN Siehe den zweiten Teil meiner Antwort, die ich aktualisiert habe. – CathalMF

1

Im Grunde ein Timer genau das tut, was es tun soll: führen Sie Ihre Code alle 0,5 Sekunden. :) Ein in Ihrem Fall, das ist ein Problem ...

(Bitte überprüfen Sie auf Syntaxfehler etc, Ich schreibe dies in Notepad)

Lange Lösung

Ihr Problem scheint zu sein, dass du deine Threads nicht kontrollierst.Hier ist, wie ich es lösen würde: (Diese lange Lösung zeigt, wie es mehr oder weniger Werke)

while (true) 
{  
    // we want to run it again in 0.5 seconds. 
    DateTime start = DateTime.UtcNow.AddSeconds(0.5); 

    Thread[] threads = new Thread[models.Count]; 
    for (int i=0; i<models.Count; ++i) 
    { 
     threads[i] = new Thread((a) => SaveServerInfo((ServerModel)a)); 
     threads[i].Start(models[i]); 
    } 

    for (int i=0; i<models.Count; ++i) 
    { 
     threads[i].Join(); 
    } 

    DateTime current = DateTime.UtcNow; 
    if (current < start) 
    { 
     Thread.Sleep(start.Subtract(current)); 
    } 

} 

Short Lösung

Doch diese können Probleme geben, wie gut: Sie könnten laichen zu viele Fäden. Dies kann mit einem Mechanismus namens Thread-Pooling gelöst werden. Wie sich herausstellt, gibt es eine einfache Möglichkeit, dies zu lösen:

static void DoStuff(string s) 
{ 
    // change to a value > 0.5 as well to ensure everything works 
    Thread.Sleep(TimeSpan.FromSeconds(0.1)); 
    Console.WriteLine(s); 
} 

static void Handle(List<string> models) 
{ 
    while (true) 
    { 
     // we want to run it again in 0.5 seconds. 
     DateTime start = DateTime.UtcNow.AddSeconds(0.5); 

     Parallel.ForEach(models, (a) => DoStuff(a)); 
     DateTime current = DateTime.UtcNow; 
     if (current < start) 
     { 
      Thread.Sleep(start.Subtract(current)); 
     } 
    } 
} 

static void Main(string[] args) 
{ 
    List<string> models = new List<string>(); 
    for (int i = 0; i < 10; ++i) 
    { 
     models.Add(i.ToString()); 
    } 

    Handle(models); 

} 
+0

das hat nicht funktioniert. Die erste Lösung hat mir eine Ausnahme außerhalb des Bereichs gegeben, sobald ich sie nicht im Debugger ausgeführt habe. Die zweite Lösung hat die Threads nur einmal ausgeführt und dann gestoppt. – ThunD3eR

+0

@ Ra3IDeN Ich habe einen Thread-Start im ersten Beispiel vergessen; das ist jetzt behoben. Die zweite Lösung funktioniert so wie sie ist. Wenn Sie eine Ausnahme außerhalb des Bereichs erhalten, ändern Sie die Sammlung in einem Thread - ** das ist in jedem Fall nicht erlaubt, Sie erstellen eine Race-Bedingung! ** Was Sie behauptet, dass es nicht funktioniert Ich habe gerade einen minimalen Testfall erstellt und es funktioniert einwandfrei; fühlen Sie sich frei, um selbst zu überprüfen. – atlaste

Verwandte Themen