2017-06-01 49 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