【发布时间】:2026-02-13 12:45:02
【问题描述】:
我正在对超过 7500 个对象运行 Parallel.For 循环。在那个 for 循环中,我对每个对象做了很多事情,特别是调用两个 Web 服务和两个内部方法。 Web 服务只是检查对象、处理并返回一个字符串,然后我将其设置为对象的属性。两种内部方法也是如此。
我没有将任何内容写入磁盘或从磁盘读取。
我还在 winforms 应用程序中使用标签和进度条更新 UI,让用户知道它在哪里。代码如下:
var task = Task.Factory.StartNew(() =>
{
Parallel.For(0, upperLimit, (i, loopState) =>
{
if (cancellationToken.IsCancellationRequested)
loopState.Stop();
lblProgressBar.Invoke(
(Action)
(() => lblProgressBar.Text = string.Format("Processing record {0} of {1}.", (progressCounter++), upperLimit)));
progByStep.Invoke(
(Action)
(() => progByStep.Value = (progressCounter - 1)));
CallSvc1(entity[i]);
Conversion1(entity[i]);
CallSvc2(entity[i]);
Conversion2(entity[i]);
});
}, cancellationToken);
这是在 Win7 32 位机器上进行的。
关于为什么当增量器在 1370 左右时突然冻结的任何想法(它一直是 1361、1365 和 1371)?
关于如何调试它并查看锁定的内容(如果有的话)有什么想法吗?
编辑:
下面对 cmets 的一些答案:
@BrokenGlass - 不,没有互操作性。我会尝试 x86 编译并告诉你。
@chibacity - 因为它在后台任务中,所以它不会冻结 UI。直到它冻结时,进度条和标签以大约每秒 2 次的速度滴答作响。当它冻结时,它就停止移动。我可以验证它停止的号码已被处理,但没有更多。双核 2.2GHz 上的 CPU 使用率在运行期间最低,为 3-4%,一旦冻结则为 1-2%。
@Henk Holterman - 到达 1360 大约需要 10 到 12 分钟,是的,我可以验证所有这些记录都已处理,但其余记录未处理。
@CodeInChaos - 谢谢,我会试试的!如果我取出并行代码,代码确实有效,它只需要永远和一天。我没试过限制线程数,但是会的。
编辑 2:
有关 web 服务发生了什么的一些细节
Web 服务的基本情况是它们传递一些数据并接收数据(一个 XmlNode)。然后在 Conversion1 过程中使用该节点,该过程又在实体上设置另一个属性,该属性被发送到 CallSvc2 方法,依此类推。它看起来像这样:
private void CallSvc1(Entity entity)
{
var svc = new MyWebService();
var node = svc.CallMethod(entity.SomeProperty);
entity.FieldToUpdate1.LoadXml(node.InnerXml);
}
private void Conversion1(Entity entity)
{
// Do some xml inspection/conversion stuff
if (entity.FieldToUpdate1.SelectSingleNode("SomeNode") == "something") {
entity.FieldToUpdate2 = SomethingThatWasConverted;
}
else {
// Do some more logic
}
}
private void CallSvc2(Entity entity)
{
var svc = new SomeOtherWebService();
var xmlNode = svc.MethodToCall(entity.FieldToUpdate2.InnerXml);
entity.AnotherXmlDocument.LoadXml(xmlNode.InnerXml);
}
如您所见,这是非常简单的事情。在一些转换方法中发生了很多事情,但没有一个应该是阻塞的。如下所述,有 1024 个线程处于“等待”状态,它们都在进行 Web 服务调用。我在这里读到http://www.albahari.com/threading/ 32 位机器上的 .Net 4 的 MaxThreads 默认为 1023。
考虑到我在这里的情况,如何释放那些等待的线程?
【问题讨论】:
-
我之前也遇到过类似的问题 - 我会尝试在 x86 模式下构建项目,看看是否有任何改变。你不会碰巧在你的任务中做任何 InterOp?
-
它是冻结还是只是非常缓慢。 CPU 使用率如何?
-
还没有使用过 TPL,但是你不能在调试器中中断并检查函数停止的方法调用吗?如果用普通的 for 循环替换它,代码是否有效?如果您使用
Parallel.For但将其限制为一两个线程会怎样? -
您应该使您的 Web 服务调用异步。 BeginGetResponse 而不是 GetResponse。这会将线程释放回池中。
-
鉴于您所说的,我认为我们需要了解 CallSvc 方法的内容。您是否有机会分享您如何调用服务的示例?是WCF、WebClient、HttpRequest……?
标签: c# parallel-processing freeze task-parallel-library