我们在应用程序中使用Task。在一个类中,我们希望触发在并行任务上运行的更新。调用如下所示:
Maintenance.RecievedMessage += new NotificationHandler(Maintenance_RecievedMessage);
Maintenance.checkLastXML = false;
Maintenance.NeedToUpdateFromCarrier(userId);
SpinWait.SpinUntil(() => isCompleted == true);
return true;因此,我们挂钩了一个事件,该事件在Maintenance.NeedToUpdateFromCarrier(userId);方法运行完成时触发。完整的方法如下所示:
private void Maintenance_RecievedMessage(IsCompleted changeargs)
{
isCompleted = true;
}所以我们在等待NeedToUpdateFromCarrier方法,一旦它完成,它就会触发事件,我们捕捉事件,并将属性isComplete设置为true,当SpinWait.SpinUntil finnaly完成时,我们继续。
由于SpinWait.SpinUntil对CPU的负担很大,我现在正在寻找一个替代方案来解决这个问题。
发布于 2012-01-21 20:24:34
重要的是要了解什么时候自旋等待是合适的。很少有情况是这样的。自旋等待优化了线程上下文切换。每当您等待某些东西时,像WaitHandle.Wait()这样的调用都会阻塞线程并产生处理器。当操作系统找到一些其他线程来执行有用的工作时,它执行线程上下文切换。
线程上下文切换是非常昂贵的。没有确切的数字,因为它取决于让出线程运行的位置,当该线程在另一个进程或保护环(驱动程序)中运行时,会有额外的开销。它的成本在2000到10000个周期之间。
这些都是cpu周期,不会完成太多任务。只是开销不能完成真正的工作。如果你知道等待条件总是少于20,000个周期,你就可以优化你的线程代码。只需延迟你的线程(旋转),就可以确保不需要昂贵的上下文切换。这不是像Thread.Sleep()那样的正常延迟,它是100%消耗内核的小循环。有了一些智能,就像在只有一个核心的机器上旋转一样,永远不会很好地工作,所以无论如何它都会让步。
显然,如果等待条件持续超过20,000个周期,这将不会很好地工作。现在你站在明智选择的另一端,你确实想在这些情况下让步。这不仅仅是为了避免在cpu不能完成任何任务时消耗cpu,尤其是因为让步现在更有可能更快地满足等待条件。因为您增加了设置等待条件的线程能够获得足够的cpu周期来完成其作业的可能性。
在您的代码中有大量的证据证明了这一点。在旋转之前,您显式地要求代码做一些事情。并且它需要一个事件处理程序来通知完成。Mucho代码需要运行。最令人信服的是,您正在看到大量cpu被消耗。在TaskMgr.exe中,1%的负载大约是2000万个cpu周期。
请使用可等待的事件,如AutoResetEvent。请注意所需的结构更改,isCompleted不能再是布尔值。在完成处理程序中调用Set(),等待()阻塞它。
发布于 2012-01-21 19:29:15
您可以使用ManualResetEventSlim
var signal = new ManualResetEventSlim();
Maintenance.RecievedMessage += delegate { signal.Set(); };
Maintenance.checkLastXML = false;
Maintenance.NeedToUpdateFromCarrier(userId);
signal.Wait();
return true;https://stackoverflow.com/questions/8952496
复制相似问题