为什么这么短 运行 时间?
Why such a short run time?
我用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();
开始一个任务 运行s 直到满意的结果到达然后退出:
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
。
我用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();
开始一个任务 运行s 直到满意的结果到达然后退出:
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
。