1

该程序是一个消息海报应用程序,可以将行发布到站点,因为它应该很快,所以我不得不使用多线程。但问题是线程数可以从 10 到 100,所以如果线程数很高2 个线程占用同一行的可能性成为可能。我怎样才能避免它?我只是想看看用相同 ID 发布的最多 11 行,这是不可能的,除了我上面假设的......

我采取行的方式如下:

1- 从数据库创建数据集....

2-创建计数器,rowCounter = 0

   while (rowCounter < allPostingRows.Tables[0].Rows.Count)
            {

           //  Take rows, and increment rowcounter++
           //  Takes row according to row counter....
          //   get the value from the fields in dataset and run the function:
               postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);
             }

因此,如果在开始时我说 100 个线程来运行它,则 100 个线程进入此代码,每个线程占用一行并发布,当一个线程发布并且空闲时,检查rowcounter, 并占用另一行。

所以我正在使用上述逻辑为线程提供不同的行。这种方法是否不好,因为我想不出任何其他方法!还假设多个线程占用相同的行,我该如何解决?

更新

我能想到的一种解决方案是在所有工作完成后随机延迟,线程去获取可能有帮助的新行?

用户回答后更新如下:

所以我的代码应该是这样的:

private Object thisLock = new Object();

   lock (thisLock)
            {
    while (rowCounter < allPostingRows.Tables[0].Rows.Count)
            {

           //  Take rows, and increment rowcounter++
           //  Takes row according to row counter....
          //   get the value from the fields in dataset and run the function:
               postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);
             }
          }
4

4 回答 4

0

是的,这种方法“不好”,您将遇到您描述的有问题的线程情况。事实上,您可以让所有 100 个线程在递增计数器之前获得相同的行。

我能想到的一种解决方案是在所有工作完成后随机延迟,线程去获取可能有帮助的新行?

不要批评,但你认为这是一个解决方案吗?我建议您阅读C# 文档中的线程和同步,以更加熟悉这些主题。

这里有几个建议。

1)反转工作流程。与其先创建线程,然后让它们来获取数据,不如让主进程在创建线程时将工作分配给线程。这样,线程在尝试访问共享资源时永远不会发生冲突,它们在完成时可能会死掉,并且可以在那时创建新的。

2) 如果 #1 对您不起作用,那么您需要将上面代码中的 while 循环视为“关键部分”,并将其放在锁定块内。 这将确保只有一个线程在给定时间获取一行并递增计数器。但是,根据线程工作的速度,这可能会降低进程的效率。

于 2012-08-11T06:40:07.933 回答
0

很明显,2 个或更多线程读取同一行的可能性;但是,我确信您可以使用锁定机制来保护关键部分。此外,ADO.NET 将支持异步任务以提高性能

于 2012-08-11T06:42:03.590 回答
0

正如 LB 指出的那样,我认为这Parallel.ForEach是你最好的选择。

有些事情要注意为什么以及如何确保你不滥用 ForEach。

执行线程使用特定的 CPU 或核心。Windows 支持任意数量的执行线程。线程数可以远远超过内核数。如果每个线程都不是 CPU 绑定的,这通常不是问题,因为通常有很多马力可以解决。CPU Bound 线程基本上是利用 100% 的核心运行。每次 Windows 从一个线程中取出一个核心以让另一个线程运行时,称为上下文切换。上下文切换非常耗时,它必须暂停一个线程,为当前线程保存所有寄存器和其他状态信息,为另一个线程加载保存的寄存器和状态信息,然后启动另一个线程。据说这本身需要多达 1000 个周期。当线程不受 CPU 限制时,上下文切换的可能性较小;但是,即使它确实发生了,通常也有很多 CPU 周期来处理它。当您有多个 CPU 绑定线程时,它们会使用所有可以使用的周期。当您开始仅仅为了在线程之间切换而取消周期时,您可能会开始注意到实际花费的时间更长。如果你的 CPU Bound 线程多于核心(即你想一次运行“100”个线程),你实际上会采取如果您按顺序而不是并行运行所有工作,则可以有更多时间来执行相同数量的工作。

Parallel.ForEach自动执行此操作。它知道拥有比内核更多的 CPU 绑定线程是一件坏事,并且只会启动与它认为合适的数量一样多的线程来执行并行工作。(通常基于核心数;但是,它对 TPL 中的其他内容有更好的了解,因此它可能具有其他使用标准)。您可以强制 ForEach 使用特定数量的线程,但您将违背并行性的目的降低性能。

如果您有 4 个内核(甚至 8 个内核)并且运行 100 个 CPU 绑定线程,则用于上下文切换的 CPU 时间量将是巨大的,并且可能会使系统陷入几乎无法使用的状态。

于 2012-08-11T15:21:52.843 回答
0

同意其他评论者关于使用更智能的分区,例如 Parallel.ForEachr 提供的分区。但是,如果您仍想使用您的代码,请考虑将计数器增量放在关键区域内,或使用 CAS 增量。在 while 循环内部而不是外部执行它。例如:

while (rowCounter < allPostingRows.Tables[0].Rows.Count)
                {
                    Interlocked.Increment(ref rowCounter);
                    //  Take rows, and increment rowcounter++            
                    //  Takes row according to row counter....           
                    //   get the value from the fields in dataset and run the function:                
                    postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);              
                }
于 2012-08-11T16:07:15.130 回答