为什么这么短的运行时间?
问题描述:
我在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);
}
答
在计时代码,你应该使用TotalMilliseconds
而非Milliseconds
。
或者只输出TimeSpan
直接:
Console.WriteLine(DateTime.Now.Subtract(start));
作为边注,Stopwatch
通常用于定时,而不是DateTime.Now
。
我在这里没有看到任何会导致提前退出的内容。但是你不显示实际设置“IsHungry”的代码。 –
我试图避免发布整个列表,但我可以,如果这将有所帮助。 –
所以你说的是测试*会运行几秒/分钟,但测试*输出*只是说它运行得更少? –