2017-06-01 48 views
0

我在C#中實現了用餐哲學家問題的解決方案(前一段時間,不記得什麼時候,不記得在哪裏),最近我重新打開它並添加了一些定時輸出。當實際測試運行需要很多秒鐘時,測試似乎只運行幾毫秒。事實上,我可以強制它運行幾分鐘,儘管測試仍然顯示小於500毫秒。爲什麼這麼短的運行時間?

簡而言之,我創建了一個任務集合,讓它們每次運行(開啓和關閉)幾秒鐘,在主執行中循環直到它們完成並寫出開始和結束時間之間的差異。

這裏正在使用NUnit的單元測試運行的解決方案:

[Test] 
public void DoesEveryOneEat_WaitsForAllToFinish() 
{ 
    // arrange 
    var start = DateTime.Now; 

    // act 
    foreach (var philosopher in Thinkers) 
    { 
     philosopher.StartEating(); 
    } 

    // wait 
    bool someoneIsHungry = true; 

    while (someoneIsHungry) 
    { 
     someoneIsHungry = false; 

     foreach (var philosopher in Thinkers) 
     { 
      if (!someoneIsHungry && philosopher.IsHungry) 
       someoneIsHungry = true; 
     } 
    } 

    Console.WriteLine(DateTime.Now.Subtract(start).Milliseconds); 

    // assert 
    Assert.AreEqual(false, Thinkers[0].IsHungry, "Philosopher 0 is hungry and ate for only " + Thinkers[0].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[1].IsHungry, "Philosopher 1 is hungry and ate for only " + Thinkers[1].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[2].IsHungry, "Philosopher 2 is hungry and ate for only " + Thinkers[2].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[3].IsHungry, "Philosopher 3 is hungry and ate for only " + Thinkers[3].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[4].IsHungry, "Philosopher 4 is hungry and ate for only " + Thinkers[4].AteForMillis + " milliseconds."); 
} 

philosopher.StartEating();開始將持續至令人滿意的結果已經到達一個任務,然後退出:

public async void StartEating() 
{ 
    await Task.Factory.StartNew(Run); 
} 

public void Run() 
{ 
    while (_totalRunTime < MaxEatMillis) 
    { 
     if (Monitor.TryEnter(Left)) 
     { 
      if (Monitor.TryEnter(Right)) 
      { 
       Eat(); 
       Monitor.Exit(Right); 
      } 
      Monitor.Exit(Left); 
     } 
    } 
} 

雖然我歡迎對此代碼的建設性意見,我的問題是:爲什麼單元測試控制檯輸出只有582毫秒,當測試本身不容易完成9秒或更多?我會推測這是因爲實際的單元測試代碼運行的時間只有582毫秒,但NUnit庫不允許斷言運行,直到測試完成所有任務開始。 ,這並不在我的腦海盛傳正確,因爲如果寫代碼,將依靠這一事實會失敗)

全面上市。

public class ChopStick 
{ 
    public int Index { get; set; } 
} 

public class Philosopher 
{ 
    protected ChopStick Left { get; set; } 
    protected ChopStick Right { get; set; } 

    private int _totalRunTime = 0; 
    private readonly int MaxEatMillis = 3000; 
    private readonly int MaxRunMillis = 1000; 

    public Philosopher(ChopStick left, ChopStick right) 
    { 
     Left = left; 
     Right = right; 
    } 

    public async void StartEating() 
    { 
     await Task.Factory.StartNew(Run); 
    } 

    public void Run() 
    { 
     while (_totalRunTime < MaxEatMillis) 
     { 
      if (Monitor.TryEnter(Left)) 
      { 
       if (Monitor.TryEnter(Right)) 
       { 
        Eat(); 
        Monitor.Exit(Right); 
       } 
       Monitor.Exit(Left); 
      } 
     } 
    } 

    private void Eat() 
    { 
     var eatTime = new Random().Next(1, MaxRunMillis); 
     Thread.Sleep(eatTime); 
     _totalRunTime += eatTime; 
    } 

    public bool IsHungry => _totalRunTime < MaxEatMillis; 

    public int AteForMillis => _totalRunTime; 
} 

[Test] 
public void DoesEveryOneEat_WaitsForAllToFinish() 
{ 
    // arrange 
    var start = DateTime.Now; 

    Console.WriteLine(DateTime.Now.Subtract(start).Milliseconds); 

    // act 
    foreach (var philosopher in Thinkers) 
    { 
     philosopher.StartEating(); 
    } 

    // wait 
    bool someoneIsHungry = true; 

    while (someoneIsHungry) 
    { 
     someoneIsHungry = false; 

     foreach (var philosopher in Thinkers) 
     { 
      if (!someoneIsHungry && philosopher.IsHungry) 
       someoneIsHungry = true; 
     } 
    } 

    Console.WriteLine(DateTime.Now.Subtract(start).Milliseconds); 

    // assert 
    Assert.AreEqual(false, Thinkers[0].IsHungry, "Philosopher 0 is hungry and ate for only " + Thinkers[0].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[1].IsHungry, "Philosopher 1 is hungry and ate for only " + Thinkers[1].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[2].IsHungry, "Philosopher 2 is hungry and ate for only " + Thinkers[2].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[3].IsHungry, "Philosopher 3 is hungry and ate for only " + Thinkers[3].AteForMillis + " milliseconds."); 
    Assert.AreEqual(false, Thinkers[4].IsHungry, "Philosopher 4 is hungry and ate for only " + Thinkers[4].AteForMillis + " milliseconds."); 

    Console.WriteLine(DateTime.Now.Subtract(start).Milliseconds); 
} 
+0

我在這裏沒有看到任何會導致提前退出的內容。但是你不顯示實際設置「IsHungry」的代碼。 –

+0

我試圖避免發佈整個列表,但我可以,如果這將有所幫助。 –

+0

所以你說的是測試*會運行幾秒/分鐘,但測試*輸出*只是說它運行得更少? –

回答

1

在計時代碼,你應該使用TotalMilliseconds而非Milliseconds

或者只輸出TimeSpan直接:

Console.WriteLine(DateTime.Now.Subtract(start)); 

作爲邊注,Stopwatch通常用於定時,而不是DateTime.Now