سؤال

how can the following method perform better?

First some background information:

A mapping between form and used logics (on a deeper layer) is put in a dictionary CtrlLogicMapping.

A control can have multiple logics (e.g. for different controls on a form).

In certain cases it is necessary to know wether an object is already inuse in one (independend which) control logics.

Each logic can have one or more mapped objectscopes, which are from a third party vendor and contain the information about objects mapped to db.

If an object is used, therefore aLogic.ObjectScope.IsUsed(ObjectID) could return true or false.

I want a method which asked every existing ObjectScope once wether the object is in it, and as soon as an objectscope has the object true should be returned (other objectscopes do no longer need to be processed. An ObjectScope can be in multiple Logics.

Not every form needs to have logics (therefore the list can be null or empty) and not every logic needs an objectscope (also there the list can be null or empty).

The InUse method is somethign which can take awhile (InUse in tests took between 60 and 140 ms).

So I want to avoid calling of InUse as much as possible, and maybe parallize it as much as possible.

The iterative solution:

internal bool InUse (string ID_in){

        List<string> checked = new List<string>();

        if (null != frmLogicMapping && 0 < frmLogicMapping.Count)
        {
            foreach (List<Logic> logics in frmLogicMapping.Values)
            {
                if (null != logics && 0 < logics.Count)
                {
                    foreach (Logic aLogic in logics)
                    {
                        if (null != aLogic.ObjectScope)
                        {
                            if (!checked.Contains(aLogic.ObjectScope.ID)) 
                            {
                                // can take up to 140 ms
                                if (aLogic.ObjectScope.InUse(ID_in)) 
                                    return true;
                                checkeded.Add(aLogic.ObjectScope.ID);
                            }
                        }
                    }
                }
            }
        }
        return false;
   }

Is there a way to paralize it with the stop criteria that InUse==true should immediatly return true and other processing should not report anything?

Or coudl it also be written somehow in PLINQ ? How can null values be handled in PLINQ? Or would normal LINQ be a better choice? (even how to handle the null values?)

What i wanted to do was something like

        if (null != frmLogicMapping&& 0 < frmLogicMapping.Count)
        {
            var objectscopes = frmLogicMapping.Values
                .Where(logics != null && logics.Count > 0)
                .SelectMany(logic => logic.ObjectScope)
                .Where(logic.ObjectScope!= null).ToList();

            bool returnValue = false;
            Parallel.ForEach(objectscopes, objectScope=>
            {
                if (objectScope.IsDirtyObject(objectID))
                {
                    returnValue  = true;
                }
            });
            return returnValue  ;
        }

but somehow i mix up the linq statement ... and i also don't know how to immediate return from parallel foreach, or how to mark the returnvalue as volatile

Thanxs, Offler


Solution so far: thanx to Stephen Borg

 if (null != objectScopes && 0 < objectScopes .Count)
        {
            System.Threading.Tasks.Task<bool>[] tasks = new System.Threading.Tasks.Task<bool>[objectScopes.Count];

            for (int i = 0; i < objectScope.Count; i++)
            {
                int temp= i;
                tasks[temp] = System.Threading.Tasks.Task.Factory.StartNew(() => { return objectScopes[temp].InUse(ID_in); }
                    , System.Threading.Tasks.TaskCreationOptions.LongRunning);
            }

            System.Threading.Tasks.Task.WaitAll(tasks);

            if (tasks.Any(x => x.Result == true))
            {
                return true;
            }
        } 

        return false;
هل كانت مفيدة؟

المحلول

Another option would be to create a method which validates the List list, and use the System.Threading.Tasks.Task, view here : http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx.

You can do something similar to this, structure wise :

            Func DummyMethod = () =>{
                return true;
            };

            // Create list of tasks
            System.Threading.Tasks.Task[] tasks = new System.Threading.Tasks.Task[2];

            // First task
            var firstTask = System.Threading.Tasks.Task.Factory.StartNew(() => DummyMethod(), TaskCreationOptions.LongRunning);
            tasks[0] = firstTask;

            // Second task
            var secondTask = System.Threading.Tasks.Task.Factory.StartNew(() => DummyMethod(), TaskCreationOptions.LongRunning);
            tasks[1] = secondTask;

            // Launch all
            System.Threading.Tasks.Task.WaitAll(tasks);

            if (tasks.Any(x => x.Result)) { 
                Console.Write("In use!");
            }

In you case you would need to loop the task results and check if any of the returned values are true. The gain would be that all the lists will be run at once, on seperate threads.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top