使用线程进行并行编程

时间:2013-06-18 10:42:47

标签: c# .net multithreading parallel-processing

好的,我对我应该做什么以及如何做有点困惑。我知道并行编程和线程理论,但这是我的情况:

我们在给定文件夹中有多个日志文件。我们在数据库中读取这些日志文件。通常读取这些文件需要几个小时才能读取,就像我们在串行方法中一样,即我们遍历每个文件,然后为每个文件打开一个SQL事务并将日志插入数据库,然后读取另一个并执行相同的操作。 / p>

现在,我正在考虑使用并行编程,因此我可以使用所有CPU的核心,但是我仍然不清楚我是否为每个文件使用Thread,这会对系统产生什么影响?我的意思是,如果我创建了30个线程,那么它们将在单核上运行还是在并行运行?我怎样才能同时使用它们?如果他们还没有这样做?

编辑:我使用单服务器,10K HDD速度和4核CPU,4 GB RAM,无网络操作,SQL Server与Windows 2008作为操作系统在同一台机器上。 [如果有帮助也可以改变操作系统:)]。

编辑2 :我根据您的反馈进行了一些测试以确定,这是我在具有4 GB RAM的i3四核CPU上找到的

  1. CPU保持在24-50%CPU1,CPU2保持低于50%的使用率,CPU3保持在75%的使用率,CPU4保持在0%左右。是的我有Visual Studio,eamil客户端和许多其他应用程序打开,但这告诉我应用程序没有使用所有核心,因为CPU4保持0%;

  2. RAM一直保持在74%[测试前大约为50%],这就是我们设计读取的方式。所以,没什么可担心的

  3. 硬盘保持读/写或使用值仍然低于25%,甚至在正弦波中飙升至25%,因为我们的SQL事务首先存储在内存中,然后在内存达到阈值时写入磁盘,再次,

  4. 因此,所有资源都在这里使用,因此我认为我可以分配工作以提高效率。你的想法了。感谢。

6 个答案:

答案 0 :(得分:2)

这个问题没有明确的答案,你必须测试,因为我在评论中提到:

  • 如果瓶颈是磁盘I / O,那么通过添加更多线程就不会获得太多收益,甚至可能会恶化性能,因为更多的线程将争取访问磁盘

    < / LI>
  • 如果您认为磁盘I / O正常但CPU负载是问题,那么您可以添加一些线程,但不超过核心数量,因为这里由于上下文切换,情况会再次恶化

  • 如果你可以做更多的磁盘和网络I / O并且CPU负载不高(非常可能)那么你可以超过(远)更多的线程而不是核心:通常如果你的线程花费了大量的时间等待数据库

所以你应该首先进行剖析,然后(或者直接,如果你赶时间)测试不同的配置,但你可能会遇到第三种情况。 :)

答案 1 :(得分:2)

首先,您需要了解您的代码以及为什么这么慢。如果您正在考虑“我的代码很慢并且使用一个CPU,那么我只会让它使用所有4个CPU并且它将快4倍”,那么您很可能是错的。

在以下情况下使用多线程是有意义的:

  1. 您的代码(或至少其中的一部分)受CPU限制。也就是说,它不会因磁盘,网络连接或数据库服务器而变慢,而是由CPU降低速度。
  2. 或者您的代码有多个部分,每个部分使用不同的资源。例如。一部分从磁盘读取,另一部分转换数据,这需要大量CPU,最后一部分将数据写入远程数据库。 (并行化实际上并不需要多个线程,但它通常是最简单的方法。)
  3. 根据你的描述,听起来你可能处于情境#2。一个很好的解决方案是生产者消费者模式:第1阶段线程从磁盘读取数据并将其放入队列。第2阶段线程从队列中获取数据,处理它们并将它们放入另一个队列。第3阶段线程从第二个队列获取已处理的数据并将它们保存到数据库中。

    在.Net 4.0中,您将BlockingCollection<T>用于线程之间的队列。当我说“线程”时,我几乎意味着Task。在.Net 4.5中,您可以使用TPL Dataflow中的块而不是线程。

    如果你这样做,那么你可以将执行速度提高三倍(如果每个阶段都需要相同的时间)。如果第2阶段是最慢的部分,那么你可以通过在该阶段使用多个线程来获得另一个加速(因为它是CPU绑定的)。这同样适用于第3阶段,具体取决于您的网络连接和数据库。

答案 2 :(得分:1)

首先,你应该检查花时间。如果CPU实际上是瓶颈,并行处理将有所帮助。也许这是网络和更快的网络连接将有所帮助。也许购买更快的光盘会有所帮助。

在考虑解决方案之前找到问题。

答案 3 :(得分:1)

您的问题不是使用所有CPU,您的操作主要是I / O(读取文件,将数据发送到DB)。

使用线程/并行将使您的代码运行得更快,因为您同时处理了许多文件。

为了回答您的问题,框架/操作系统将优化在不同核心上运行您的代码。

答案 4 :(得分:1)

它因机器而异,但一般来说,如果你有一个双核心处理器并且你有2个线程,操作系统会将一个线程传递给一个核心而另一个线程传递给另一个核心。无论您使用多少核心,重要的是您的等式是否最快。如果您想使用并行编程,您需要一种以逻辑上有意义的方式共享工作负载的方法。您还需要考虑瓶颈实际发生的位置。根据文件的大小,它可能只是读取/写入存储介质的最大速度,这需要花费很长时间。作为测试,我建议您记录代码中消耗时间最多的位置。

测试非串行方法是否对您有所帮助的一种简单方法是按顺序对文件进行排序,将工作负载分配到同时执行相同作业的2个线程之间,看看它是否有所不同。如果第二个线程没有帮助你,那么我保证30个线程只会花费更长时间,因为操作系统必须将线程切换回第四个。

答案 5 :(得分:1)

使用.Net 4中的最新结构进行并行编程,通常会为您管理线程...阅读getting started with parallel programming (与最近发生的事情几乎相同,如果你想让它同步,可以使用异步版本的函数)

e.g。

for (int i = 2; i < 20; i++)
{
    var result = SumRootN(i);
    Console.WriteLine("root {0} : {1} ", i, result);
}

变为

Parallel.For(2, 20, (i) =>
{
    var result = SumRootN(i);
    Console.WriteLine("root {0} : {1} ", i, result);
});

编辑:也就是说,将密集型任务放入单独的线程中可能会更高效/更快......但要手动使您的应用程序“多核”并具有某些线程之类的东西在特定的核心上运行,这是目前无法实现的,这些都是在引擎盖下进行管理......

plinq为例 和.Net Parallel Extensions 并研究

System.Diagnostics.Process.GetCurrentProcess().ProcessorAffinity = 4

<强> EDIT2 : 并行处理可以在具有多个线程的单个内核中完成。

多核处理意味着分配这些线程以利用CPU中的多个核心。