使用TimeSpan.FromTicks延迟任务是否正确?

时间:2014-02-16 13:41:21

标签: c# task delay timespan

我的程序需要尽可能快地执行许多重复计算。并行运行的许多任务导致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中

?如果是,那么如何确定用户何时可以使用它?

2 个答案:

答案 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...

取消您只需清空队列。