我的程序需要尽可能快地执行许多重复计算。并行运行的许多任务导致CPU利用率达到100%。为了让用户减慢处理过载(略低于100%的CPU,取决于硬件),我添加了
await Task.Delay(TimeSpan.FromMilliseconds(doubleProcessingCycleIntervalMilliseconds));
重型加工方法。只要doubleProcessingCycleIntervalMilliseconds的值至少为1 ms,这就完美无缺。 对于拥有高端计算机的用户(计算速度将小于1毫秒),我想为延迟添加相同的选项,而不是使用刻度的毫秒。所以现在代码看起来:
if (ProcessingCycleIntervalOptionsMilliseconds == true)
{
await Task.Delay(TimeSpan.FromMilliseconds(doubleProcessingCycleIntervalMilliseconds));
}
else
{
await Task.Delay(TimeSpan.FromTicks(longProcessingCycleIntervalTicks));
}
当longProcessingCycleIntervalTicks的walue至少10000个ticks(= 1ms)时,程序工作正常。不幸的是,当值低于1ms(0表示doubleProcessingCycleIntervalMilliseconds,我可以理解)或10000以下(即9999对于longProcessingCycleIntervalTicks)程序变得无响应。因此字面上1个刻度低于1毫秒的差异挂起了程序。我不使用MVVM。 (以防万一:我检查了Stopwatch.IsHighResolution在开发计算机上给出了真实情况)
使用
是否可行/正确await Task.Delay(TimeSpan.FromTicks(longProcessingCycleIntervalTicks));
在.NET 4.5.1中?如果是,那么如何确定用户何时可以使用它?
答案 0 :(得分:3)
您的意图不是将CPU利用率保持在100%以下。您的目的是保持系统的响应能力。限制CPU利用率是一个错误的目标。
执行此操作的方法是使用低优先级线程。 Use a custom task scheduler for your CPU bound tasks.
Windows中的时序精度有限。 Thread.Sleep
无法使用小数毫秒。 .NET将它们移交给Sleep
。
答案 1 :(得分:1)
你可能最好不要看你执行任务的方式,而不是试着睡觉。
我能想到的最好方法是使用任务管理器独立管理每个任务(例如后台工作者),然后线程化任务集合。
这将使您能够管理正在运行的任务数量,而不是试图“减慢”它们的速度。
即
public class Task<returnType>
{
public delegate returnType funcTask(params object[] args);
public delegate void returnCallback(returnType ret);
public funcTask myTask;
public event returnCallback Callback;
public Task(funcTask myTask, returnCallback Callback)
{
this.myTask = myTask;
this.Callback = Callback;
}
public void DoWork(params object[] args)
{
if (this.Callback != null)
{
this.Callback(myTask(args));
}
else
{
throw new Exception("no Callback!");
}
}
}
然后你需要一个管理员,其中包含你要完成的任务的队列,调用myQueue.Enqueue
排队,myQueue.Dequeue
来运行任务。基本上,您可以使用已经内置的Queue来执行此操作。
然后,您可以创建一个充满任务的任务管理器队列,并让它们全部以异步方式运行,并在CPU上进行很好的堆叠,因为它们是事件驱动的,操作系统和.NET将对其余部分进行排序。
编辑: 要继续运行任务,您需要创建一个继承Queue类的类,然后在出现某些内容时调用一个事件。我说使用事件的原因在于它们堆叠在CPU上。
对于一个无休止的可堆叠'循环'这样的东西会起作用......
public class TaskManager<T> : Queue<T>
{
public delegate void taskDequeued();
public event taskDequeued OnTaskDequeued;
public override T Dequeue()
{
T ret = base.Dequeue();
if (OnTaskDequeued != null) OnTaskDequeued();
return ret;
}
}
在实例化'循环'的函数中,您需要执行类似......
的操作TaskManager<Task<int>> tasks = new TaskManager<Task<int>>();
Task<int> task = new Task<int>(i => 3 + 4, WriteIntToScreen); // WriteIntToScreen is a fake function to use as the callback
tasks.Enqueue(task);
tasks.OnTaskDequeued += delegate
{
tasks.Enqueue(task);
tasks.Dequeue.Invoke();
};
// start the routine with
tasks.Dequeue.Invoke(); // you call do some async threading here with BeginInvoke or something but I am not gonna write all that out as it will be pages...
取消您只需清空队列。