我正在开发一个分析实时财务数据的应用程序。目前,我的主要计算周期具有以下设计:
long cycle_counter=0;
while (process_data)
{
(analyse data, issue instruction - 5000 lines of straightforwasrd code with computations)
cycle_counter++;
Thread.Sleep(5);
}
当我在笔记本(一个核心i5)处理器上运行此应用程序时,该周期每秒运行200-205次 - 一种预期的(如果您不考虑为什么它运行的每秒超过200倍以上))。
但是,当我将应用程序部署在"真实"工作站上时,该应用程序具有2个6核Xeon处理器和24 GB的快速RAM,并且在大约3秒内加载Win7时,该应用程序将每秒运行约67次。
我的问题是:
为什么会发生这种情况?
在这种情况下我如何影响每秒运行的数量?
是否有更好的解决方案来运行每秒200-1000次的周期?我现在正在考虑删除thread.sleep()(我在这里使用它的方式受到了很多批评)。对于12个核心,我仅在此周期中使用一个核心就没有问题。但是我对这种解决方案有一些缺点?
谢谢您的想法。
您所采用的方法根本是断裂的。一般而言,投票策略是一种不好的方法,除了"我想让其余的时间恢复到操作系统"之外,任何其他原因,您都可能做错了。p>解决问题的更好方法是:
- 将无处理作品的线程列为螺纹范围
- 制作一个将新作品排在队列中的线程
- 使n个线程从队列中锻炼并进行工作。 n应该是您的CPU数量。
- 工人线程除了坐在循环中,从队列中锻炼并完成工作。
- 如果队列为空,则"删除" 块。
- 当新作品到达时,一个被阻塞的线程被重新激活。
如何使用这些属性建立队列是一个著名的问题,称为生产者/消费者问题。关于如何执行任何阻止生产者 - 消费者队列的实现,有很多文章。我建议找到一个现有的调试,而不是试图编写自己的调试;正确正确可能很棘手。
Windows不是RTO(实时操作系统),因此您无法精确确定线程何时恢复。Thread.Sleep(5)
确实意味着"不久就将我唤醒5ms"。实际的睡眠时间由特定的硬件决定,主要由系统负载决定。您可以通过更高的优先级运行应用程序来尝试解决system load
问题。
btw,system.threading.timer是一种更好的方法(上面的注释仍然适用)。
睡眠的分辨率由当前的计时器tick间隔决定,通常是10或15毫秒,具体取决于Windows的版本。但是,可以通过发出timeBeginperiod命令来更改这。请参阅此答案。
检查您的计时器的实际频率:许多硬件计时器具有实际分辨率
65536 ticks per hour = 65536 / 3600 = 18.204 ticks per second
所谓的" 18.2"常数,这就是为什么实际计时器的分辨率为 1/18.2 = 55 ms ;对于Sleep(5)
,这意味着可以是Sleep(0)
或Sleep(55)
,具体取决于圆形。
不确定它是最好的方法,而是另一种方法。
尝试BlockingCollection,您在生产者中所做的就是添加和睡眠。
然后,消费者可以在需要时选择全职工作。
这仍然无法解释为什么较高功率的PC持续更少的周期。
您可以平均运行200次循环?
var delay = TimeSpan.FromMillseconds(5);
while (process_data) {
Console.WriteLine("do work");
var now = DateTime.Now;
if (now < nextDue)
System.Threading.Thread.Sleep(nextDue - now);
nextDue = nextDue.Add(delay);
}
使用此技术,您的循环会在某种程度上执行,但平均应该可以,因为代码既不取决于Sleep
的分辨率,也不取决于DateTime.Now
的分辨率。
您甚至可以将此方法与计时器相结合。