首页 文章

使用线程进行并行编程

提问于
浏览
1

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

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

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

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

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

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

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

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

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

6 回答

  • 2

    首先,您需要了解您的代码以及为什么它会变慢 . 如果你只是让它使用所有4个CPU,它将快4倍“,那么你很可能是错的 .

    在以下情况下使用多个线程

    • 您的代码(或至少其中的一部分)受CPU限制 . 也就是说,它被你的CPU放慢了速度 .

    • 或者您的代码有多个部分,每个部分使用不同的资源 . 例如 . 一部分从磁盘读取,另一部分转换数据,这需要大量CPU,最后一部分将数据写入远程数据库 . (并行化这通常是最简单的方法 . )

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

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

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

  • 1

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

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

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

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

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

  • 1

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

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

  • 1

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

    由于您同时处理许多文件,因此使用线程/并行将使您的代码运行得更快 .

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

  • 2

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

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

  • 1

    使用.Net 4中的最新构造进行并行编程,通常为您管理线程...读取getting started with parallel programming(与最近发生的事件几乎相同,如果您希望它同步,则使用异步版本的函数)

    例如

    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);
    });
    

    EDIT :也就是说,将密集型任务放入单独的线程中会有效率/更快......但是要手动创建应用程序'Multi-Core'并且在特定内核上运行某些线程,这些都是在引擎盖下管理的...

    看看例如plinq.Net Parallel Extensions并查看

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

    Edit2 :并行处理可以在具有多个线程的单个内核中完成 .

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

相关问题