Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 并行执行带参数的方法_C#_Task_Task Parallel Library - Fatal编程技术网

C# 并行执行带参数的方法

C# 并行执行带参数的方法,c#,task,task-parallel-library,C#,Task,Task Parallel Library,我不熟悉异步和并行编程,我的问题围绕着尝试运行一个包含两个参数的方法,然后并行执行该方法。我需要并行运行此程序,因为调用的方法正在更新我工厂车间的PLC。如果它是同步关闭,这个过程可能需要近10分钟,因为有多少。我可以使用自定义类中的最后一个PLC使该方法运行一次,但不会为列表中的其他PLC运行。示例代码如下: List<Task> task = new List<Task>(); foreach(PLC plc in PlcCollection) { strin

我不熟悉异步和并行编程,我的问题围绕着尝试运行一个包含两个参数的方法,然后并行执行该方法。我需要并行运行此程序,因为调用的方法正在更新我工厂车间的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
}
但是,我仍然只能运行其中一个任务。调试器屏幕截图如下,仅显示2个PLC中的1个已更新。我应该看到一个控制台行说“PLC更新为TTC_墙”。

问题可能是您的代码没有等待任务完成。您可以使用阻塞方法等待它们全部完成

这样,当前线程将被阻塞,直到所有任务完成,并且可能发生的任何异常都将在
aggregateeexception
中捆绑显示

上述方法假设
MakeTagsAsync
方法是真正异步的。如果不是,而是通过在
Task.Run
中内部包装一些同步代码来假装异步。首先,您应该了解为什么这是一个坏主意:然后通过删除
Task.Run
包装并将返回类型更改为
void
,使方法再次同步,并使用
Parallel
类或PLINQ库并行调用该方法。以下是一个例子:


您想一次调用所有PLC的
MakeTags
,还是想?为什么要使用
Task.Run()
?此调用将线程池上的工作线程排队,这是不必要的,因为
MakeTags()
是异步的,可能是IO绑定的。您只需将
MakeTags(plcName,tagFormat)
添加到
Task
列表中,然后使用
Task.WhenAll()等待结果。此外,您不需要使用
Parallel.ForEach
来“开始”工作。调用
Task.Run()
时,一个线程将排入线程池队列,并将在任务计划程序允许的情况下运行。在调用异步方法的情况下,它们在被调用时开始。@PatrickTucci我正在使用Task.Run(),因为这是我对如何设置任务的理解-这是我第一次尝试异步编程,学习起来很有挑战性。如果我理解你的意思,我应该尝试以下操作:
tasks.Add(MakeTags(plcName,tagFormat)
然后
Task.whalll(tasks.ToArray())
?@JohnMuraski一个
任务
只代表一个异步操作。它不是线程或并行的简写。区别很重要,你应该研究,但不在评论讨论的范围内。要回答你的问题,是的,你发布的代码应该做你想做的。值得注意的是,如果
MakeTags()
包含CPU密集型代码,这可能会给服务器带来很大的负载。如果它是IO绑定的,这应该不是问题。问题很可能出在
MakeTags
中。谢谢Theodor Zoulias和@Patrick Tucci!我在上面的答案中使用了PLINQ方法,它起到了作用。我的方法开始并行运行!仍然有很多问题需要解决学习并行编程,但这是一个很好的开始。@JohnMuraski如果您想控制并行度,PLINQ包含一个
带degreeofparallelism
操作符,您可以在
AsParallel
操作符之后附加该操作符。请注意,并行性还受到
线程池可用性的进一步限制ode>threads。当
ThreadPool
饱和时,它会以较慢的速度注入新线程。因此,请记住在程序开始时使用
ThreadPool.SetMinThreads
方法的选项,以配置(增加)
ThreadPool
根据需要立即创建的最小线程数。
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;
}
Task[] tasks = PlcCollection
    .Select(plc => MakeTagsAsync(plc.Name, plc.TagFormat))
    .ToArray();
Task.WaitAll(tasks);
Console.WriteLine("****PLC Update Complete*****");
PlcCollection
    .AsParallel()
    .ForAll(plc => MakeTags(plc.Name, plc.TagFormat));
Console.WriteLine("****PLC Update Complete*****");