C#多线程:微线程睡眠的开销

时间:2009-08-31 16:42:31

标签: c# multithreading

我有一个抓取另一个桌面快照的应用程序。此过程在单独的后台工作线程中异步放置和运行。 DoWork活动的小型模型是:

private void GrabImage_DoWork(object sender, DoWorkEventArgs e)
{
 /*Grab the image..*/
 System.Threading.Thread.Sleep(10)
}

目前已经放置了一个thread.sleep(10),我只是想知道这种小睡眠是否会因为不断增加的不需要的上下文切换而导致性能下降。

如果问题需要进一步解释,请告诉我。 欢呼声,

编辑: 决定抛出一堆更多的背景,以帮助专注于一个特定的答案。

提出的问题 问:这是目前运行的唯一后台线程吗? 答:不会。实际上有一些后台工作线程以及一个使用.NET Threadpool类将多个线程排队的线程。因此,最初将睡眠放入代码中以考虑允许对这些其他线程进行上下文切换。 但是我仍然相信无论如何操作系统是时间切片的,所以我确定没有睡眠,其他线程将有机会执行?

问:这个后台工作人员是否一直在运行? 答:应用程序提供了一个界面,通过切换按钮与桌面交互以显示背景图像。 因此,如果切换按钮,背景工作者基本上可以关闭或不断搅拌。

我希望整体问题对于表现来说似乎并不总是不重要。我试图在性能和可用性之间找到一个很好的平衡。

4 个答案:

答案 0 :(得分:4)

睡眠可能会导致额外的上下文切换,因为它将允许其他线程在您的进程中执行。

但是,听起来你有一个后台工作线程。如果是这种情况,您可能会进行上下文切换。这种情况往往发生在后台工作者报告进度的任何时候(因为他们正在跨线程调用)。有一个,我怀疑你会注意到所涉及的性能损失,尽管唯一的方法是确定你的应用程序。

我更大的问题是:为什么你首先在这里添加这个睡眠,特别是如果你担心的话。通常,您在此处添加一个睡眠,以允许其他线程工作,这通常会导致上下文切换。如果你是按照设计做到的,那么就不用担心了。如果你没有需要这个睡眠,另一方面,没有理由包含它。


编辑:以下是回复编辑的一些细节:

  问:这是目前唯一运行的后台线程吗?答:不会。实际上有一些后台工作线程以及一个使用.NET Threadpool类将多个线程排队的线程。因此,最初将睡眠放入代码中以考虑允许对这些其他线程进行上下文切换。但是我仍然相信无论如何操作系统是时间切片的,所以我确定没有睡眠,其他线程将有机会执行?

操作系统将进行时间片,但(默认情况下)此线程将具有默认优先级。理论上,它应该获得与主线程和其他线程运行一样多的处理器时间。你不必睡觉,但有时这是有利的(见下文)。

  问:这个后台工作人员是否一直在运行?答:应用程序提供了一个界面,通过切换按钮与桌面交互以显示背景图像。因此,如果切换按钮,背景工作者基本上可以关闭或不断搅拌。

如果工作线程将要处于循环中并且只是不断地占用CPU,那么添加一些机制以防止它耗尽整个CPU核心通常是有利的(除非你需要在该线程中实时执行) 。小睡眠(虽然睡眠(0)也适用于此)是一个简单的选择。但是,如果算法对此有意义,通常更好的是将某种类型的WaitHandle放在适当的位置,这样你就可以根据需要工作了。这实际上取决于算法。

  

由于我已经在使用Threadpool类,因此将此工作负载排队到threadpool类而不是sepearte后台工作者。

BackgroundWorker类使用ThreadPool线程,因此这样做没有真正的优势。然而,BackgroundWorker使得针对UI线程工作变得更加简单,因此如果您在UI上显示您的进度,那么使用BW可能更容易,就像您现在所做的那样。

答案 1 :(得分:1)

绝对可以,但这完全取决于执行此代码的上下文。回答问题的最佳方法是分析应用程序以查看此代码是否会产生瓶颈。

答案 2 :(得分:0)

使用睡眠:

  • 可能会增加总CPU时间(因为进入睡眠状态和唤醒所需的开销)
  • 会增加任务的挂钟时间(因为即使没有必要也会睡觉)

另一种选择可能是使用优先级较低的线程而不是睡眠。

答案 3 :(得分:0)

为什么要睡觉?如果你让线程只睡眠一次进行同步,那么同步机制将是不可预测的,并且应该更加健壮,以容忍网络延迟的巨大差异。

Thread.Sleep(int)的所有调用都会导致上下文切换。由于Windows是桌面计算操作系统,因此调度粒度可以提高感知响应速度,但是经验法则大约10-20毫秒很长。

如果快照抓取方法不经常运行,则根本不会产生性能开销,而是允许系统的其余部分保持响应,因为您可以为其他准备运行的线程提供CPU时间。如果您不想产生CPU切片,请改用Thread.SpinWait(int)。为了重复调用Thread.Sleep(int)等待另一个操作完成,我建议使用至少20毫秒的休眠间隔,以确保其他线程/进程实际上有时间完成其工作。