多线程资源争用

时间:2011-10-20 05:00:28

标签: .net multithreading profiling contention

我正在分析一个运行不同数量的允许线程的多线程程序。以下是同一输入工作的三次运行的性能结果。

1 thread:
  Total thread time: 60 minutes.
  Total wall clock time: 60 minutes.

10 threads:
  Total thread time: 80 minutes. (Worked 33% longer)
  Total wall clock time: 18 minutes.  3.3 times speed up

20 threads
  Total thread time: 120 minutes. (Worked 100% longer)
  Total wall clock time: 12 minutes.  5 times speed up

由于需要更多的线程时间来完成同样的工作,我觉得线程必须争夺资源。

我已经检查过app机器和数据库服务器上的四个支柱(cpu,内存,diskIO,网络)。内存是最初的竞争资源,但现在已经修复(任何时候都超过1G)。在20线程测试中,CPU徘徊在30%到70%之间,因此很多。在应用程序计算机上,diskIO几乎没有,在数据库服务器上几乎没有。网络真的很棒。

我还使用redgate进行代码分析,并且看不到等待锁的方法。它有助于线程不共享实例。现在我正在检查更多细微差别的项目,例如数据库连接建立/池化(如果20个线程尝试连接到同一个数据库,它们是否必须彼此等待?)。

我正在尝试识别并解决资源争用问题,以便20线程运行如下:

20 threads
  Total thread time: 60 minutes. (Worked 0% longer)
  Total wall clock time: 6 minutes.  10 times speed up

为了找到这种争论,我应该考虑哪些最有可能的来源(除了大四)?


每个线程执行的代码大约是:

Run ~50 compiled LinqToSql queries
Run ILOG Rules
Call WCF Service which runs ~50 compiled LinqToSql queries, returns some data
Run more ILOG Rules
Call another WCF service which uses devexpress to render a pdf, returns as binary data
Store pdf to network
Use LinqToSql to update/insert. DTC is involved: multiple databases, one server.

WCF服务在同一台计算机上运行,​​并且是无状态的,能够同时处理多个请求。


机器有8个cpu。

3 个答案:

答案 0 :(得分:3)

你所描述的是你想要100%的可扩展性,这是线程增加和wallcklock时间减少之间的1:1关系......这通常是一个目标,但很难达到......

例如,您写道没有内存争用,因为有1 GB可用...这是恕我直言错误的假设...内存争用还意味着如果两个线程尝试分配内存,可能会发生一个必须等待另一个...要记住的另一个问题是GC发生的中断暂时冻结所有线程...... GC可以通过配置(gcServer)进行一些定制 - 请参阅http://blogs.msdn.com/b/clyon/archive/2004/09/08/226981.aspx

另一点是WCF服务被称为...如果它无法扩展 - 例如PDF渲染 - 那么这也是一种争用的形式,例如......

可能的争用列表是“无休止的”......并且几乎不会总是在你提到的明显区域......

编辑 - 根据评论:

要检查的一些要点:

  • 连接池
    你用什么提供商?它是如何配置的?
  • PDF渲染
    可能会在您使用的库内某处测量可能的争用...
  • LINQ2SQL
    检查所有这些查询的执行计划......可能有些人采取任何类型的锁定,因此可能会产生争用数据库服务器端......

编辑2:

<强>线程
这些线程来自ThreadPool吗?如果是这样,那么你就不会缩放: - (

编辑3:

ThreadPool线程对于长时间运行的任务是不利的,在您的场景中就是这种情况......有关详细信息,请参阅

来自http://www.yoda.arachsys.com/csharp/threads/printable.shtml

  

长时间运行的操作应该使用新创建的线程;   短期运行可以利用线程池。

如果您想获得极致性能,则可能需要查看CQRS以及描述为LMAX的真实示例。

答案 1 :(得分:2)

不是测量总线程时间,而是测量执行某些操作的操作的时间(数据库,磁盘,网络等)。

我怀疑你会发现当你有更多的线程时,这些操作需要更长的时间,这是因为争用是在那个I / O的另一端。例如,您的数据库可能正在序列化数据一致性请求。

答案 2 :(得分:2)

是的,有资源争用。例如,所有线程必须将数据读/写到同一存储器总线,并指向相同的RAM模块。无论有多少RAM是空闲的,重要的是读/写由相同RAM模块上的相同存储器控制器执行,并且数据通过同一总线传输。

如果任何地方有任何类型的同步,那么这也是一个竞争资源。如果有任何 I / O,那就是竞争资源。

从1线程到N线程时,你永远不会看到N x加速。这是不可能的,因为最终,CPU中的所有是一个共享资源,会有一定程度的争用。

有很多因素阻止您获得全线性加速。您假设数据库,运行数据库的服务器,将其连接到客户端的网络,客户端计算机,两端的操作系统和驱动程序,内存子系统,磁盘I / O和所有内容< / em>介于两者之间时,从1到20个线程可以快20倍。

两个字:梦想。

这些瓶颈中的每一个都只能让你减慢几个百分点,然后整体结果会像你所看到的那样。

我相信你可以调整它以更好地扩展,但不要指望奇迹。

但您可能会寻找的一件事是缓存线共享。线程是否访问与其他线程使用的数据非常接近的数据?你多久可以避免这种情况发生?