c# - 并行执行带参数的方法
问题描述
我是异步和并行编程的新手,我的问题围绕着尝试运行一个采用几个参数的方法,然后并行执行该方法。我需要并行运行它,因为被调用的方法是更新我工厂车间的 PLC。如果它同步关闭,这个过程可能需要将近 10 分钟,因为有多少。我可以使用自定义类中的最后一个 PLC 使该方法运行一次,但不会为列表中的其他 PLC 运行。下面的示例代码:
List<Task> task = new List<Task>();
foreach(PLC plc in PlcCollection)
{
string plcName = plc.Name;
string tagFormat = plc.TagFormat
tasks.Add(Task.Run(async () => await MakeTags(plcName, tagFormat)));
}
Parallel.ForEach(tasks, task => task.Start());
// Code to be done after tasks are complete
public async Task MakeTags(string plcName, string tagFormat)
{
//Code to update the PLC's
}
makeTags 方法的工作方式与调用时应有的一样 - 它正确更新 PLC。但它只运行一次,并且只针对我的一个 PLC 值。我也试过Task.WhenAll(tasks)
代替Parallel.ForEach
, 有同样的问题。有没有人对我做错了什么以及我可以尝试的任何事情有任何建议和反馈?谢谢!
编辑:澄清 - 我希望 MakeTags 方法可以并行执行,但 PlcCollection 中有许多 PLC(数量将是可变的)。我得到的是 MakeTags 方法只被调用一次,对于一个 PLC 元素,当集合中有多个 PLC 时。此过程从 Web 应用程序开始,然后服务器负责其余的工作。没有 UI 元素被更新或更改。这一切都在幕后工作。
编辑 2:有关调试器的屏幕截图,请参见下文。在这个例子中,2 个 PLC(TTC_WALL 和 RR_HEPA_EE)被加载到我的任务列表中。但是,只有 RR_HEPA_EE 被处理,然后程序完成而不会引发异常。
编辑 3:我进行了更改,现在代码如下所示:
List<Task> task = new List<Task>();
foreach(PLC plc in PlcCollection)
{
//plcName and tagFormat are just strings
tasks.Add(MakeTags(plcName, tagFormat);
}
Task.WhenAll(tasks).ContinueWith(t =>
{
//Code to do
Console.WriteLine("****PLC Update Complete*****");
});
return; //program ends
public async Task MakeTags(string plcName, string tagFormat)
{
await Task.Run(() =>
{
Console.WriteLine("Updating PLC " + plcName);
//Code to update the PLC's
Console.WriteLine("PLC Updated for :" + plcName);
});
return;
}
但是,我仍然只能运行其中一项任务。下面的调试器屏幕截图显示 2 个 PLC 中只有 1 个已更新。我应该会看到一条控制台行,上面写着“为 TTC_WALL 更新了 PLC”。
解决方案
问题可能是您的代码没有等待任务完成。Task.WaitAll
您可以使用阻塞方法等待它们全部完成。
Task[] tasks = PlcCollection
.Select(plc => MakeTagsAsync(plc.Name, plc.TagFormat))
.ToArray();
Task.WaitAll(tasks);
Console.WriteLine("****PLC Update Complete*****");
这样,当前线程将被阻塞,直到所有任务都完成,并且任何可能发生的异常都将被捆绑在一个AggregateException
.
上述方法假定该MakeTagsAsync
方法是真正异步的。如果不是,而是通过在内部包装一些同步代码来伪造异步Task.Run
,首先您应该在这里阅读为什么这是一个坏主意:我应该为同步方法公开异步包装器吗?Task.Run
然后通过删除包装器并将返回类型更改为再次使方法同步void
,并使用Parallel
类或 PLINQ 库并行调用该方法。这是一个PLINQ示例:
PlcCollection
.AsParallel()
.ForAll(plc => MakeTags(plc.Name, plc.TagFormat));
Console.WriteLine("****PLC Update Complete*****");
推荐阅读
- express - Nestjs MiddlewareConsumer 排除路径在 Azure 函数中不起作用
- geometry - 检查矩形是否与空间中的任何矩形相交的快速算法
- java - Maven 部署/安装未解决
- linux - Linux键盘/终端/内核输入缓冲区
- c# - SQL/C#:DataTable 到存储过程(从用户定义的表类型插入)- 转换错误
- asp.net - 使用 Twilio 和 asp.net Webforms 接收 SMS
- css - ::具有不透明度属性的首字母伪元素不起作用
- php - 添加默认值与 created_at 相同的 updated_at 列
- javascript - 如何在表格中打印/渲染 Firebase 信息 REACT JS
- powerbi - 我可以在订阅周期结束前取消 Power BI 高级版每次使用许可证吗