2

Very new to .NET task parallelism. The objective is walking through a tree structure, where each branch is composed of one parent node, one child node and one operation node(like a weight). And for each node, create an extension object and save it to db. I followed a possible duplicate conversation. But the observation is that the tree is not walked through completely. The process would exit early unexpectedly. Following is my code:

public void InitializeScheduleVariables_Parallel(IResource ANode, double aNumRequired, double aBatchRequired, double aAcceptProbability, AppContext aAppContext, bool ARecursively = true)
    {
        var LTasks = new List<Task>();
        var LUser = aAppContext.LocalContext.User;
        LTasks.Add(Task.Factory.StartNew(() =>
        {
            var LNewContext = new AppContext(new DbContext(new Context(LUser)));
            var LNewRep = new ResourceRepository(LNewContext);
            ANode = LNewRep.Get(ANode.Id);

            ANode.ResourceInstance_Create(); // Create the ResourceInstance on the Resourse if it not already exists.
            ANode.ResourceInstance.Required = aNumRequired;
            ANode.ResourceInstance.ScheduleSource = ResourceInstance.ScheduleSourceEnum.Undefined;
            ANode.ResourceInstance.ScheduleState = ResourceInstance.ScheduleStateEnum.Unscheduled;
            ANode.ResourceInstance.ScheduleMode = ResourceInstance.ScheduleModeEnum.Undefined;
            ANode.ResourceInstance.BatchRequired = aBatchRequired;
            ANode.ResourceInstance.ProbabilityOfCompletion = aAcceptProbability;
            ANode.ResourceInstance.Save();
        }));

        if (ARecursively)
        {
            foreach (AssemblyLink LAssembly in ANode.GetOutEdges())
            {
                LTasks.Add(Task.Factory.StartNew(() =>
                {
                    // SET The Variables for the Production Operations AS WELL
                    IOperationResource LOperation = LAssembly.Operation;
                    if (LOperation != null)
                    {
                        var LNewContext = new AppContext(new DbContext(new Context(LUser)));
                        var LNewRep = new OperationResourceRepository(LNewContext);
                        LOperation = LNewRep.Get(LOperation.Id);

                        LOperation.ResourceInstance_Create(); // Create the ResourceInstance on the Resourse if it not already exists.
                        LOperation.ResourceInstance.Required = aNumRequired / LAssembly.OutputQuantity;
                        LOperation.ResourceInstance.BatchRequired = aBatchRequired / LAssembly.OutputQuantity;
                        LOperation.ResourceInstance.ScheduleSource = ResourceInstance.ScheduleSourceEnum.Undefined;
                        LOperation.ResourceInstance.ScheduleState = ResourceInstance.ScheduleStateEnum.Unscheduled;
                        LOperation.ResourceInstance.ScheduleMode = ResourceInstance.ScheduleModeEnum.Undefined;
                        LOperation.ResourceInstance.ProbabilityOfCompletion = aAcceptProbability;
                        LOperation.ResourceInstance.Save();
                    }
                }));

                LTasks.Add(Task.Factory.StartNew(() =>
                {
                    // Recursively SET Child NODES 
                    IResource LChildNode = LAssembly.Child;
                    double LNumRequired_Child = aNumRequired * LAssembly.InputQuantity / LAssembly.OutputQuantity;
                    double LNumBatchRequired_Child = LChildNode.Quantity * LAssembly.InputQuantity / LAssembly.OutputQuantity;
                    InitializeScheduleVariables_Parallel(LChildNode, LNumRequired_Child, LNumBatchRequired_Child, aAcceptProbability, aAppContext, ARecursively);
                }));
            }
        }
        Task.WaitAll(LTasks.ToArray());
    }

Could anyone share some thought? Thank you.

Community
  • 1
  • 1
ritchxu
  • 151
  • 1
  • 1
  • 5
  • It is not a very good idea to try to parallelize everything. Your context is not Thread-Safe and you're not using any locking. Do you really want to have that stuff in parallel? If yes, why? Do you think the performance will be better or what exactly is the target? premature optimization is the root of all evil. Here is much wrong or not really good. The structure, the mix of the responsibility of code, the namings.... And overall, if that would be your next step: never cascade parallel tasks. – Benjamin Abt Jan 26 '16 at 13:44
  • Ben, Thanks for your comment, the reason I want to use parallelism here is creating the extension object in sequence would linearly increase the process time as the tree grows if done synchronously, and I don't care the sequence, so I thought maybe doing them in parallel could take advantage of CPU and decrease the processing time. For thread safety, I attempt to create new context, which contains its own db context, I thought this way they would be separate and would not incur thread safety issue. Am I wrong about it? – ritchxu Jan 26 '16 at 13:53
  • Yes, because it's hurts all modern approaches of code seperation, modularization, responsibility, code security, lose coupling.. testability etc etc. A new context is also a risk because there is always a limit of available handles to create a context. You should better use or evaluate scalable architectures like [TPL Pipelining](https://msdn.microsoft.com/en-us/library/ff963548.aspx). But your code - I am really sorry for that - is content for a chamber of horrors ;-) – Benjamin Abt Jan 26 '16 at 14:01
  • I don't see what would cause the described issue in this code. Could you post [a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve)? – svick Feb 28 '16 at 14:53
  • @svick Thank you for your comment. It turned out later that the reason was the code above was traversing a tree which was not complete since the tree was being created in parallel. I then abandoned the idea of parallelism for the task above. – ritchxu Feb 29 '16 at 18:16

0 Answers0