2016-03-22 27 views
0

這個問題分兩部分。 我有一個控制檯應用程序,它從幾臺服務器獲取信息並將此信息保存到數據庫。爲了enabel這執行simultaniously我已經使用線程。我正在嘗試每分鐘自動執行一次該執行。如何正確執行線程每分鐘?

搜索計算器我發現,這可能是工作:

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); 

然而,由於預期這不工作,只執行一次。如果我改變例如這樣的:

TimeSpan.FromMinutes(0.5).Seconds 

或者:

TimeSpan.FromSeconds(30).Seconds 

然後,它的工作原理。 我在做什麼錯?這個問題的

第二部分:

當這個實際工作,因爲我上面顯示出別的東西發生。 該進程連續運行,在474個線程崩潰之後,系統表示系統內存不足。

我嘗試過使用線程睡眠,但是當我這樣做時,它會在一次被毀壞後停止執行。

包括這一點,如果它可能會幫助:

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

} 

我怎樣才能使這項工作?

+2

「TimeSpan.FromMinutes(1).Seconds」返回0。你要「TimeSpan.FromMinutes(1).TotalSeconds」返回60 –

+0

我會使用'TimeSpan'重載。 _https://msdn.microsoft.com/en-us/library/ah1h85ch(v = vs.110).aspx_ –

+0

'TimeSpan.FromSeconds(60).Seconds'?! –

回答

2

在第一個問題中,使用.Seconds將僅返回秒值,但您將分鐘值定義爲.5,因此秒總是爲零。

如果你想回到你需要使用TotalSeconds

TimeSpan.FromMinutes(0.5).TotalSeconds 

,並在你使用你應該定義毫秒的時間跨度秒。所以你得到了大量的線程,因爲它每30毫秒運行一次,而不是每30000毫秒。

所以使用

TimeSpan.FromMinutes(0.5).TotalMilliseconds 

還是什麼,我總是更容易找到

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

試過,它每秒運行一次,直到我有475個線程,然後崩潰 – ThunD3eR

+0

因此,執行需要比間隔更長的時間。這是一個性能問題。你應該嘗試別的... –

+0

@ Ra3IDeN看到我更新的答案的第二部分。 – CathalMF

1

基本上是一個計時器不正是它應該做的:運行代碼每0.5秒。 :)一個在你的情況,這是一個問題......

(請檢查語法錯誤等,我在記事本寫這篇)

長期解決方案

你的問題似乎是你不控制你的線程。以下是我想解決這個問題:(這種長期的解決方案展示瞭如何或多或少作品)

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)); 
    } 

} 

簡短的解決方案

然而,這可能會給你的問題,以及:你可能產卵太多線程。這可以通過稱爲線程池的機制來解決。事實證明,有解決這個簡單的方法:

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

這沒有奏效。一旦我沒有在調試器中運行它,第一次soloution給了我一個索引超出範圍的異常。第二種解決方案只運行一次線程,然後停止。 – ThunD3eR

+0

@ Ra3IDeN我在第一個例子中忘記了一個線程開始;現在已經修復了。第二種解決方案按原樣運行。如果你的索引超出範圍異常,你正在改變線程中的集合 - **在任何情況下都不允許,你正在創建一個競爭條件!**至於你聲稱它不起作用,我剛創建了一個最小的測試用例,它的工作正常;隨時檢查自己。 – atlaste