C# 多线程不处理所有任务

C# 多线程不处理所有任务,c#,multithreading,for-loop,parallel-processing,C#,Multithreading,For Loop,Parallel Processing,我使用下面的代码来执行一项使用线程的任务,这里我尝试执行“dtTable”数据表中的所有记录。有限线程数为2(即,此时仅允许两个线程/执行)。问题是它并没有执行Datatable中所有可用的记录,而是以不规则的方式执行数据。有什么问题吗。。?提前谢谢 public class Generator : IDisposable { public static int maxThreadCount = 2; public static int runningThreadCount

我使用下面的代码来执行一项使用线程的任务,这里我尝试执行“dtTable”数据表中的所有记录。有限线程数为2(即,此时仅允许两个线程/执行)。问题是它并没有执行Datatable中所有可用的记录,而是以不规则的方式执行数据。有什么问题吗。。?提前谢谢

 public class Generator : IDisposable
 {
    public static int maxThreadCount = 2;
    public static int runningThreadCount = 0;

    public RunTask()
    {
       for (int ro = 0; ro <= dtTable.Rows.Count - 1; ro++)
       {
          if (maxThreadCount > runningThreadCount)
          {
            Thread atpthread = new Thread(delegate()
            {
            DoOperationMethod(dtTable.Rows[ro], Task, startDate, EndDate, dtTemplate);
            });
            atpthread.Start();
            runningThreadCount = runningThreadCount + 1;
            Mainthreads.Add(atpthread);
          }
          else
          {
            ro--;
          }
       }
  }

  public void DoOperationMethod(DataRow drAttachpoint, System.StrTaskItem Task, DateTime startDate, DateTime EndDate, DataTable dtTemplate)
    {
     //doing my Operation
     runningThreadCount = runningThreadCount-1; //Once Task done count will get reduce
    }
公共类生成器:IDisposable
{
公共静态int maxThreadCount=2;
公共静态int runningThreadCount=0;
公共运行任务()
{
对于(int ro=0;ro runningThreadCount)
{
线程atpthread=新线程(委托()
{
DoOperationMethod(dtTable.Rows[ro]、任务、开始日期、结束日期、dtTemplate);
});
atpthread.Start();
runningThreadCount=runningThreadCount+1;
Mainthreads.Add(atpthread);
}
其他的
{
ro--;
}
}
}
public void操作方法(DataRow drAttachpoint、System.strTask、DateTime startDate、DateTime EndDate、DataTable dtTemplate)
{
//做我的手术
runningThreadCount=runningThreadCount-1;//一旦任务完成,计数将减少
}
}


我使用的是.net 3.5(仅供参考)。

问题是,在等待线程释放时,您不断迭代数据表中的行。在任何情况下,这种多线程处理,即使它实际上是正确的(它不是),也是非常低效的——大部分时间可能都花在启动新线程上

请尝试以下方法:

Parallel
 .ForEach(dtTable.Rows.OfType<DataRow>(), row => DoOperationMethod(...))
 .WithDegreeOfParallelism(2);
并行
.ForEach(dtTable.Rows.OfType(),row=>DoOperationMethod(…)
.平行度(2);
编辑:

为了弄清楚问题是如何产生的,您必须了解在匿名方法中如何捕获变量。您的
DoOperationMethod
调用没有被传递到所需的数据行,因为
ro
“变量”没有被复制,而是被引用。因此,当
ro
在循环中更改时,它也会在您创建的线程中更改

这与您的代码非常不安全且效率低下的事实不同:

  • 实际上,您正在浪费三个线程来完成工作—在没有阻塞的情况下,您的循环只是不断地添加和减去
    ro
    ,这几乎完全是纯CPU工作。这比等待结果时简单地阻塞要浪费得多
  • 您不能只从多个线程读取和写入静态字段,而期望事情正常工作。实际上,您的代码很容易并行启动比您希望的更多的线程,甚至在没有线程运行的情况下,通过
    runningThread
    将整个过程死锁为
    2
  • 您不断启动新线程来执行一个看似微不足道的操作——我猜您的大部分工作要么是I/O绑定的,要么是由一次又一次创建新线程的成本控制的
  • 我假设
    Mainthreads
    是某种类型的列表,并且我假设您也从
    DoOperationMethod
    方法修改它-同样,这可能会导致随机异常和意外结果
  • 理论上,由于各种优化和缓存,检查
    maxThreadCount>runningThreadCount
    可能永远不会被评估。实际上,在x86 CPU上的当前.NET上,对于像这样复杂的方法来说,这种情况不太可能发生,但当您更新到.NET 7.0或其他版本时,这种情况可能会影响您:)

多线程是很难的。你真的不想到处猜谜。至少,首先要试着理解基本知识。

在我看来,您的代码最大的问题是,即使您修复了线程不安全地使用
runningThreadCount
,您的代码在等待某个线程完成时仍在“旋转”。当您试图完成实际工作时,这会完全占用CPU核心

Luan提出的解决方案很好,尽管我会使用
Cast()
而不是
of type()
(因为枚举中的所有元素实际上都应该是
DataRow
类型)。除了简洁性之外,它还有一个很大的优势,那就是它使用了线程池,这将大大减少线程管理的开销(因为它重用线程,而不是一次又一次地创建和销毁线程)

如果您喜欢更显式的方法,可以修改发布的代码以使用信号量:

SemaphoreSlim semaphore = new SemaphoreSlim(2);

for (int ro = 0; ro <= dtTable.Rows.Count - 1; ro++)
{
    semaphore.Wait();

    DataRow row = dtTable.Rows[ro];

    Thread atpthread = new Thread(delegate()
    {
        DoOperationMethod(row, Task, startDate, EndDate, dtTemplate);
        semaphore.Release();
    });
    atpthread.Start();
    Mainthreads.Add(atpthread);
}
SemaphoreSlim semaphore=新的SemaphoreSlim(2);

对于(int ro=0;ro您可以发布其余的代码吗?它可能与
runningThreadCount
有关,这似乎表明您在多个线程中同时更改,但我们无法确定看到该代码。
DoOperationMethod
似乎直接与
DataTable
一起工作,但由于
DataTablee> 不是线程安全的。您可能会遇到问题。我们需要查看代码以确认。感谢您的神秘性,我添加了其余的代码,您会说-“问题是,您在等待线程释放时不断迭代数据表中的行。”你能说出为什么会出现这个问题吗?当然。线程中代码的执行要花费两次以上的循环迭代时间(否则首先使用多线程就没有什么意义了)。然而,这也意味着不需要等待,就可以“释放”线程(例如,
runningThreadCount--
或类似;是的,我知道它非常不安全),您在没有对其中的几行进行任何操作的情况下,成功地迭代了其中的几行-也就是说,它们被完全跳过了。很抱歉,我可能太笨了,但我不明白这是如何解释原因的。@Enigmativity:问题是,
ro
被匿名方法捕获,但它的值在