1

I am working on an issue dealing with the speed of our intranet web application and a function that gets the descendants of all items in our database.

I do not have access to the code at home, but I can describe the issue and process:

We have a database table that stores items that can be linked to a parent item in the same table. We have logic that prevents circular references, so in theory the descendant link should never circle back (so far no such thing has happened).

When a user accesses a page on the web app, currently I have functions that get the list of descendants of that item and puts it into an object. This was originally done in a normal FOR loop, but the time it took to parse through 881 entities would take 12+ seconds, which needs to change. I looked into threading and implemented the Parallel FOR loop, and it took the time from 12+ seconds to 1-2 seconds, except I randomly get errors on the page.

Some of the errors include the drop down list not being populated, the connection state not being open and available, and connection being closed and not available.

The original code is something like:

var DS = _uow.locations.AllEager().FirstOrDefault( l => l.Zone == "DS");
var hwddl = new List<HWTXSelectItem>();
var HWinDS = _uow.hw.AllEager().Where(h => h.Locations_ID == DSS.Locations_ID).OrderBy(h => h.ID).ToArray();

var dataSet =_uow.hw.AllEager().Where(h => h.IsActive && h.Parent_ID != null).Select(h => new HierarchyObject() {id=h.HW_ID, parentId = Parent_ID}).ToList();
var assets = _uow.hw.AllEager();
var arrayCount = HWinDS.Length;
for(int i = 0; i < arrayCount; i++){
    var hw in HWinDS[i];
    var HWDescendants = Helpers.FindAllChildren(dataSet, new HierarchyObject() {id=hw.HWID, parendId=null}).ToList();
    var descendends = new List<int>();
descendends.AddRange(HWDescendants.Select(m => m.id);

    var allChildren = assets.Where(h => descendends.Contains(h.HW_ID) && IsActive).ToList();

    var direct = allChildren.Where(h => h.ParentID == hw.HW_ID).Select(h => new{hwid = h.HWID, id=h.HW_ID}).OrderBy(h => h.hwid).ToList();
    var sub = allChildren.Where(h => h.Parent_ID != hw.HW_ID).Select(h => new{hwid = h.HWID, id=h.HW_ID}).OrderBy(h => h.hwid).ToList();

    hwtxddl.Add(new HWTXSelectItem
    {
    ...
    ... <obj properties>
    ...
    });
}

HWFromDS = hwddl;

The parallelized is something like:

var DS = _uow.locations.AllEager().FirstOrDefault( l => l.Zone == "DS");
var hwddl = new List<HWSelectItem>();
var HWinDS = _uow.hw.AllEager().Where(h => h.Locations_ID == DS.Locations_ID).OrderBy(h => h.ID).ToArray();

var dataSet =_uow.hw.AllEager().Where(h => h.IsActive && h.Parent_ID != null).Select(h => new HierarchyObject() {id=h.HW_ID, parentId = Parent_ID}).ToList();
var items = _uow.hw.AllEager();
var arrayCount = HWinDS.Length;
Parallel.For(0, arrayCount,i =>
{
    var hw in HWinDS[i];
    var HWDescendants = Helpers.FindAllChildren(dataSet, new HierarchyObject() {id=hw.HW_ID, parendId=null}).ToList();
    var descendends = new List<int>();
descendends.AddRange(HWDescendants.Select(m => m.id);

    var allChildren = assets.Where(h => descendends.Contains(h.HWAssets_ID) && IsActive).ToList();

    var direct = allChildren.Where(h => h.Parent_ID == hw.HW_ID).Select(h => new{hwid = h.HWID, id=h.HW_ID}).OrderBy(h => h.hwid).ToList();
    var sub = allChildren.Where(h => h.Parent_ID != hw.HW_ID).Select(h => new{hwid = h.HWID, id=h.HW_ID}).OrderBy(h => h.hwid).ToList();

    hwddl.Add(new HWSelectItem
    {
    ...
    ... <obj properties>
    ...
    });
}

HWFromDS = hwddl;

I have some variations of parallel for loops that work and speed up the process, getting an overall time of 6 seconds with partial data returning and no errors and 1 second with all data returning with random errors. The one above seems to work with full data returning but gives the random errors at random points. Any tips?

  • 1
    `hwddl.Add(` cannot be used inside a parallel loop since `List.Add` is not thread-safe. – mjwills May 15 '18 at 13:28
  • Possible duplicate of [List thread safety](https://stackoverflow.com/questions/5020486/listt-thread-safety) – mjwills May 15 '18 at 13:29
  • I am not having an issue with thread safety in that way (ive since moved from list to concurrentbag, but now I will try other thread safe methods). The issue I am having is random errors with "The connection is closed. The connection state is closing..." etc related errors that I cannot get around. – Notmah Name May 16 '18 at 12:35
  • Try using Parallel.Invoke and check if the errors still persist, I understand that Parallel.Invoke would not suit your scenario but it will help you to pinpoint the problem if there is any because of Parallel.Foreach – Utkarsh Bais Jun 01 '18 at 09:36

0 Answers0