【问题标题】:Multithreading of method call (data retrieval from SQL Server) is slower than procedural version方法调用的多线程(从 SQL Server 检索数据)比过程版本慢
【发布时间】:2012-07-18 10:55:38
【问题描述】:
// procedural 
foreach (var foo in bar)
{                                 
    foo.someProperty = getData(ref foo);     
}

// threaded
foreach (var foo in bar)
{                                         
    ThreadStart work = delegate
    {
        getData(ref foo);
    };

   new Thread(work).Start();    
}

getData(ref foo){

    // Either  a LINQ query 

    // Or Exec Command to Stored procedure in SQL Server

    // Either taking approx 2 seconds to return results

    foo.someProperty = resultsFromDBOrLinqStatement;
}

如果 bar 有 20 个项目,那么简单地使用程序 foreach 循环大约需要 10 秒 - 一个接一个地执行一个请求,每次都调用数据库。

如果对于相同的数据,使用每个循环的线程请求需要更长的时间?!看起来即使线程都很好,但来自每个线程的对 DB 的请求仍在阻止。

如果我将 getData() 方法修改为;

getData(ref foo){

    thread.sleep(4000);
}

然后,正如预期的那样,整个请求在 4 秒内完成 - 所有线程几乎同时启动,并在 4 秒后同时退出。

我是否缺少与每个线程中的 DB 调用相关的东西,这会减慢整个过程的速度? - 一些用于与 DB 等并发连接的 web.config 设置?

PS。我尝试过并行 foreach 和 Tasks,但它总是回到线程与数据库调用一起减慢速度,就好像数据库服务器正在排队所有调用一样。

【问题讨论】:

  • 你怎么知道所有的线程已经执行完毕才能测量时间?在您显示的代码的线程版本中,您只是启动线程但没有同步点。
  • 每条 0.5 秒 - 相当慢 - 猜测 getData 正在执行相当数量的 SQL - 如果它在线程版本中较慢,您可能会遇到一些死锁
  • 我目前有一个基本的监视器(在测试时),它在创建每个线程时递增一个线程计数器,并在每个线程调用 GetData 完成后递减计数器。

标签: c# asp.net-mvc .net-4.0


【解决方案1】:

当创建线程的成本(时间、资源)小于过程执行时间的总和时,多线程会产生效果。

【讨论】:

    【解决方案2】:

    只有满足所有以下条件时,对 SQL 服务器(或任何其他数据库服务器)的并行请求才会更快:

    1. 服务器为每个传入请求提供一个空闲处理器内核(实际上每个请求使用一个线程)
    2. 每个传入的请求都涉及不同的文件(数据库、表...取决于实际的服务器)
    3. 每批文件(每个请求一个)位于其自己的 HDD 上
    4. 服务器有足够的可用物理内存来同时处理所有请求和所有相关数据
    5. 服务器进程不会耗尽内存(不太可能,但在 32 位系统上,如果您请求大量数据...)

    (如果您的服务器有 SSD,则第 2 点和第 3 点无关紧要 - 在 SSD 上,并行和顺序读取多个文件的累积时间大致相同)

    在任何其他情况下,您只有一种方法可以使您的程序更快(除了获得更快的服务器,这并不总是可能的):通过减少服务器的工作来使每个请求本身更快(使用存储过程,缓存结果在临时表中,减少大型连接...)。

    【讨论】:

      猜你喜欢
      • 2011-03-01
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 1970-01-01
      相关资源
      最近更新 更多