C# 多线程不处理所有任务
我使用下面的代码来执行一项使用线程的任务,这里我尝试执行“dtTable”数据表中的所有记录。有限线程数为2(即,此时仅允许两个线程/执行)。问题是它并没有执行Datatable中所有可用的记录,而是以不规则的方式执行数据。有什么问题吗。。?提前谢谢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
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
在循环中更改时,它也会在您创建的线程中更改
这与您的代码非常不安全且效率低下的事实不同:
- 实际上,您正在浪费三个线程来完成工作—在没有阻塞的情况下,您的循环只是不断地添加和减去
,这几乎完全是纯CPU工作。这比等待结果时简单地阻塞要浪费得多ro
- 您不能只从多个线程读取和写入静态字段,而期望事情正常工作。实际上,您的代码很容易并行启动比您希望的更多的线程,甚至在没有线程运行的情况下,通过
将整个过程死锁为runningThread
2
- 您不断启动新线程来执行一个看似微不足道的操作——我猜您的大部分工作要么是I/O绑定的,要么是由一次又一次创建新线程的成本控制的
- 我假设
是某种类型的列表,并且我假设您也从Mainthreads
方法修改它-同样,这可能会导致随机异常和意外结果DoOperationMethod
- 理论上,由于各种优化和缓存,检查
可能永远不会被评估。实际上,在x86 CPU上的当前.NET上,对于像这样复杂的方法来说,这种情况不太可能发生,但当您更新到.NET 7.0或其他版本时,这种情况可能会影响您:)maxThreadCount>runningThreadCount
多线程是很难的。你真的不想到处猜谜。至少,首先要试着理解基本知识。在我看来,您的代码最大的问题是,即使您修复了线程不安全地使用
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
被匿名方法捕获,但它的值在