在同步中花费的线程时间是否过高?

时间:2011-11-29 20:03:45

标签: c# multithreading performance concurrency micro-optimization

今天我使用Visual Studio 2010性能分析器分析了我的一个C#应用程序。具体来说,我正在分析“并发”,因为看起来我的应用程序应该具有更多的容量,然后才能进行演示。分析报告显示,线程在同步状态下花费了大约70-80%的时间。

说实话,我不确定这意味着什么。这是否意味着应用程序遭受了锁定状态?

对于上下文......有大约30个长时间运行的线程绑定到单个AppDomain(如果重要的话, )并且一些线程非常繁忙(例如while(true) { _waitEvent.WaitOne(0); //do stuff } )。

我意识到这是一个相当模糊的问题......我想我正在寻找关于线程同步状态含义的一些说明。太多了,为什么? ~75%真的很糟糕吗?我有太多线程吗?或者我应该开始寻找其他领域?

3 个答案:

答案 0 :(得分:14)

  

我不确定这意味着什么。

这意味着线程平均花费75%的时间等待另一个线程完成一些工作。

  

这是否意味着应用程序遇到了锁定状态?

也许吧!

为不熟悉该术语的读者澄清:“死锁”是指两个线程都在等待彼此完成,因此他们会永远等待。 “实时锁定”是两个线程试图避免死锁的情况,但由于选择不当,无论如何都要花大部分时间等待。想象一下,例如一张有两个人的桌子,一把叉子和一把刀。两个人都希望拿起两个器具,使用它们,然后放下它们。假设我拿起刀子你拿起叉子。如果我们都决定等待对方放下器具,我们就陷入僵局。如果我们都意识到我们即将陷入僵局,我放下刀子,你放下叉子然后然后我拿起叉子拿起刀子,我们活着 - 锁定。我们可以无限期地重复这个过程;我们都在努力解决这个问题,但我们没有足够的沟通来实际快速解决问题。

然而,我的猜测是你没有处于锁定状态。我的猜测是,您只需要对少量关键资源进行大量争用,这些资源一次只能由一个线程访问。 Occam的Razor表明你应该假设一个简单的假设 - 许多线程轮流使用稀缺资源 - 而不是复杂的假设 - 一大堆线程都试图告诉对方“不,你先走”。

  

有大约30个长时间运行的线程绑定到单个AppDomain(如果这很重要)并且一些线程非常繁忙(例如,(true){_ waitEvent.WaitOne(0); // do stuff} )。

听起来很糟糕。

  

我意识到这是一个相当含糊的问题。

是的,是的。

  

多少钱,为什么?

好吧,假设你正试图穿越城镇,你和城里的其他所有司机花了75%的时间停在交通灯等待其他司机。你告诉我:那太多了,为什么?花一个小时的交通来驾驶15分钟的距离可能是一些人完全可以接受的,而其他人完全不能接受。每次我在高峰时间乘坐SR 520,我都要花一个小时的时间来移动距离,这需要15分钟。这是我不能接受的,所以现在我坐公共汽车。

您和您的客户是否接受这种糟糕的表现是您的电话。修复性能问题昂贵。您应该问的问题是,通过承担诊断和解决问题的费用,您将获得多少利润。

  

~75%真的很糟糕吗?

你的线程所需的时间比他们需要的时间长四倍。对我来说似乎不太好。

  

我有太多线程吗?

你几乎可以肯定,是的。 30很多。

但在您的情况下,这完全是错误的技术问题。问“我有太多线程吗?”通过询问“这个城市有太多的汽车吗?”试图解决交通拥堵问题。正确的问题是“为什么这个城市有这么多交通信号灯可能有高速公路?“问题不在于线索; 问题是,他们正在等待彼此,而不是在不停止的情况下开车到目的地。

  

我应该开始寻找其他领域吗?

我们怎么知道?

答案 1 :(得分:2)

如果不真正了解程序的结构,我只能真正告诉你 Synchronization 对于线程的意义。我无法告诉你程序中的问题是什么。

同步基本上意味着您协调,以便在必须对这些线程共享的资源执行操作时说并发运行线程,以避免您的数据损坏

例如,如果您的两个线程正在写入string,那么,如果您没有线程同步(即使用AutoResetEvents或Semaphores等),那么一个线程可能在以某种方式改变字符串的中间,被操作系统中断(可能它的时间片已经开启),现在第二个线程可能从这个字符串开始读取,这个字符串处于不确定状态。这会对您的程序产生影响,因此为了避免此类事情以及线程可能导致的许多其他可能的错误,您同步访问共享资源,通过锁定它,所以一次只有一个线程可以写入/读取它,而任何其他想要这样做的线程另一个正在这样做,必须等到我们的第一个帖子已经释放了它所拥有的锁。

这是一个非常简单的解释,是什么线程同步意味着什么。它是什么 线程附带的东西还有很多,但这是整本书的主题。

至于你的“线程同步状态”可能意味着什么,我猜它意味着很多线程都花时间等待持有一些共享资源的其他线程。

基本上这意味着你的程序实际上并不工作并发,而是在串行中做事,因为线程花费时间在其他线程上等待。这意味着该程序并不能很好地兼顾真正的同时工作,顺便说一下,实现并不一定是一件容易的事,取决于具体情况,显然。

希望这有帮助。

答案 2 :(得分:1)

线程同步有几种方法可以扼杀性能:

  1. 实现同步的指令需要时间来执行,特别是对于需要转换到内核模式的同步例程,例如Thread.Sleep()。在最糟糕的情况下,频繁调用同步例程的单独线程会引入大量开销,但没有真正的好处。
  2. 每当多个线程需要同时对资源进行独占访问时,至少有一个线程会等待。这里最糟糕的情况是,每个人都需要经常访问一些中央资源。在这种情况下,多线程代码很有可能成为一次使用一个线程的昂贵,缓慢和复杂的方法。
  3. 至于多少:同步是需要时间但却没有做任何有用工作的事情。因此,从性能角度来看,理想的同步量始终为零。因此,无共享体系结构和immutable data structures的高价值。两者都是帮助组织代码以消除或减少同步需求的技术。

    当然,世界并不理想,所以一定程度的同步通常是不可避免的。但即便如此,也应该使用最轻的构造物来完成。例如,Interlocked中的方法可以使用锁定语句。或者通过设计线程将工作产品批量发送到中央数据结构,而不是进行大量的高频更新来降低需要发生的频率。