Reputation: 174
I have a problem implementing Parallel.ForEach in DTable. Following is the sample code that I am implementing:
Parallel.ForEach(dTable4.AsEnumerable(), row4 =>
{
string getCondition = row4[1].ToString();
getCondition = EvaluateCondExpression(getCondition); //Evaluates CM for value (CM1==2 && CM2<5);
Expression e = new Expression(getCondition); //getCondition = (2==2 && 2<5)
var evalutateCondition = e.Evaluate();
if (Convert.ToBoolean(evalutateCondition))
{
//Write string to TextBox
}
}
When I run this, the threads are not efficiently managed and it takes far too time than foreach loop. EvaluateCondExpression function returns value after checking the user provided parameter from GUI combobox and numericUpDown
private string EvaluateCondExpression(string getCondition)
{
string[] splitgetCondition1 = SeprateCharacter(getCondition);
foreach (string oneCondition in splitgetCondition1)
{
string conditionValue = oneCondition;
if (oneCondition.Contains("CM"))
{
conditionValue = RemoveMultipleChar(conditionValue.Replace('!', ' ').Trim());
string getInputNumber = getTableOneInputNo(conditionValue, dTable1);
string tableOneValue = checkComboxValue(m_comboBox, getInputNumber);
getCondition = getCondition.Replace(conditionValue, tableOneValue);
}
}
return getCondition;
}
The serial ForEach computation is taking too much time so I wanted to apply Parallel.ForEach iteration but unfortunately it is not working. Can anyone suggest me how to maximize the performance and what I am doing wrong in Parallel.ForEach.
Upvotes: 1
Views: 2727
Reputation: 371
How long does it take to run one iteration of the loop? How many iterations are you running? In general, Parallel.Foreach() is well suited to running through loops where each iteration potentially takes quite a while. If you instead have many iterations of a relatively fast operation, you will spend a lot of extra overhead generating and managing threads, which is probably what you're seeing. See this MSDN article for more information on this type of scenario:
https://msdn.microsoft.com/en-us/library/dd560853(v=vs.110).aspx
Update
Here is a good comparison of Parallel.Foreach() and await Task.WhenAll().
Upvotes: 2
Reputation: 11478
You can make the following modification to the code, when using Parallel.ForEach
, especially for the long running tasks
Parallel.ForEach( dTable4.AsEnumerable(), new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount}, row4 = >
This would ensure that Parallel.ForEach will not start a thread of each data point in the datatable
, it will only spawn the threads based on number of environment processors / cores dynamically, thus will reduce the contention and thread context switching. However ideally as suggested above you may plan Asynchronous pattern for long running tasks.
As I see you are updating the UI control inside Parallel loop, for that you anyway need UI thread context, else it will an exception. Async anyway run in UI thread context
Upvotes: 2
Reputation: 7414
You might see a performance increase by using a traditional foreach, wrapping each iteration in a Task. Add the task for each iteration to a collection, then outside of the foreach call Task.WhenAll(tasks); if anything it gains you the ability to await the expensive parallel process.
You can convert the contents of your Parallel.ForEach in to a Select Linq query that turns each iteration in to a Task. The resulting collection of Tasks can be given to the Task.WhenAll method to await
await Task.WhenAll(dtable4.AsEnumerable().Select(row4 => new Task(() =>
{
string getCondition = row4[1].ToString();
getCondition = EvaluateCondExpression(getCondition); //Evaluates CM for value (CM1==2 && CM2<5);
Expression e = new Expression(getCondition); //getCondition = (2==2 && 2<5)
var evalutateCondition = e.Evaluate();
if (Convert.ToBoolean(evalutateCondition))
{
//Write string to TextBox
}
})));
This might not solve the performance bottle neck you're seeing, but this will at least let you await the parallel process and free up the UI thread.
Upvotes: 3