1

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

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

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

编辑:我使用的是单服务器,具有 10K 硬盘速度和 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. HDD 保持 READ/Write 或使用值保持低于 25% 甚至在正弦波中飙升至 25%,因为我们的 SQL 事务首先存储在内存中,然后在内存达到阈值时写入磁盘,所以再次,

所以这里的所有资源都没有得到充分利用,因此我认为我可以分配工作以提高效率。又是你的想法。谢谢。

4

6 回答 6

2

这个问题没有明确的答案,您必须进行测试,因为正如我的评论中提到的:

  • 如果瓶颈是磁盘 I/O,那么添加更多线程不会获得太多收益,甚至可能会降低性能,因为更多线程将争夺对磁盘的访问权限

  • 如果您认为磁盘 I/O 没问题,但 CPU 负载是问题,那么您可以添加一些线程,但不能超过内核数量,因为这里的情况又会因上下文切换而恶化

  • 如果您可以执行更多磁盘和网络 I/O 并且 CPU 负载不高(很可能),那么您可以超额订阅(远)比内核更多的线程:通常如果您的线程花费大量时间等待数据库

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

于 2013-06-18T11:13:14.677 回答
2

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

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

  1. 您的代码(或至少其中的一部分)受 CPU 限制。也就是说,它不会因为您的磁盘、网络连接或数据库服务器而变慢,而是因为您的 CPU 变慢了。
  2. 或者您的代码有多个部分,每个部分使用不同的资源。例如,一部分从磁盘读取,另一部分转换数据,这需要大量 CPU,最后一部分将数据写入远程数据库。(并行化这实际上并不需要多个线程,但它通常是最简单的方法。)

根据您的描述,听起来您可能处于第二种情况。一个很好的解决方案是生产者消费者模式:阶段 1 线程从磁盘读取数据并将其放入队列中。阶段 2 线程从队列中获取数据,处理它们并将它们放入另一个队列。阶段 3 线程从第二个队列中取出处理后的数据并将它们保存到数据库中。

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

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

于 2013-06-18T14:22:28.263 回答
1

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

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

于 2013-06-18T10:47:35.860 回答
1

使用 .Net 4 中的最新结构进行并行编程,通常会为您管理线程......阅读并行编程入门 (与最近使用异步版本的函数发生的情况几乎相同,如果您想要它异步)

例如

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 中的多个内核。

于 2013-06-18T11:23:53.453 回答
1

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

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

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

于 2013-06-18T10:49:15.367 回答
1

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

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

于 2013-06-18T10:50:10.687 回答