Few days back, we got into a very interesting performance problem -- To display around 7K data grid entries over a wide spectrum of internet connections. We had to solve the following --
The conceptual solution that manifested itself was --
Of course, the actual solution will be not to use the background worker threads because they are neither scalable nor robust. But, I just wanted to validate the concept and it works! I will be posting the real production design in the coming days.
Here is the technical breakdown of the concept --
1. Data Segmentation & Atlas Code --
Have a GridView within GridView(the nested GridView is hosted within a table, which sits inside a ItemTemplate). Nesting of child GridView within a table gives it a more cleaner look -- My colleague Sajay came up with this idea as he just couldn't bear the screen design that I initially had :)
Host the parent GridView under an UpdatePanel
<
//Child Columns here
</
</td>
</tr>
</table>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</atlas:UpdatePanel>
2. Prefetching of data --
/// This class is a singleton
{
_instance =
}
public List<Parent> GetParentList() { //Build the parent list from the persistent storage //Queue the thread so that we can start building activities for the loaded resources ThreadPool.QueueUserWorkItem(new WaitCallback(BuildChildCache)); return _parentList; }
public List<Parent> GetParentList()
//Build the parent list from the persistent storage //Queue the thread so that we can start building activities for the loaded resources ThreadPool.QueueUserWorkItem(new WaitCallback(BuildChildCache)); return _parentList;
//Build the parent list from the persistent storage
//Queue the thread so that we can start building activities for the loaded resources
protected void BuildChildCache(object state) { if ( _parentList != null && _parentList.Count > 0) { foreach (Parent parent in _parentList) { if ( parent.Children == null ) { List<Children> children = GetChildrenFromPersistentStorage( parent.ID ); //Lock the parent object so that the synchronous thread can't get to it lock( parent ) { parent.Children = children; } } } } }
protected void BuildChildCache(object state)
if ( _parentList != null && _parentList.Count > 0) { foreach (Parent parent in _parentList) { if ( parent.Children == null ) { List<Children> children = GetChildrenFromPersistentStorage( parent.ID ); //Lock the parent object so that the synchronous thread can't get to it lock( parent ) { parent.Children = children; } } } }
if ( _parentList != null && _parentList.Count > 0)
foreach (Parent parent in _parentList) { if ( parent.Children == null ) { List<Children> children = GetChildrenFromPersistentStorage( parent.ID ); //Lock the parent object so that the synchronous thread can't get to it lock( parent ) { parent.Children = children; } } }
foreach (Parent parent in _parentList)
if ( parent.Children == null ) { List<Children> children = GetChildrenFromPersistentStorage( parent.ID ); //Lock the parent object so that the synchronous thread can't get to it lock( parent ) { parent.Children = children; } }
if ( parent.Children == null )
List<Children> children = GetChildrenFromPersistentStorage( parent.ID ); //Lock the parent object so that the synchronous thread can't get to it lock( parent ) { parent.Children = children; }
List<Children> children = GetChildrenFromPersistentStorage( parent.ID );
//Lock the parent object so that the synchronous thread can't get to it
lock( parent )
parent.Children = children;
public
List<Child> children = GetChildrenFromCache( parentID ); if (children == null) { List<Child> children = GetChildrenFromPersistentStorage( parentID ); Parent parent = GetParentFromCache(parentID); //lock the parent so that the background thread can't get to it lock( parent ) { parent.Children = children; } } return children;
List<Child> children = GetChildrenFromCache( parentID );
if (children == null)
List<Child> children = GetChildrenFromPersistentStorage( parentID ); Parent parent = GetParentFromCache(parentID); //lock the parent so that the background thread can't get to it lock( parent ) { parent.Children = children; }
List<Child> children = GetChildrenFromPersistentStorage( parentID );
Parent parent = GetParentFromCache(parentID);
//lock the parent so that the background thread can't get to it
return children;
private TEManager()
Now, all that needs to be done is to pass the parentID of the selected row on the SelectedIndexChanged event to the TEManager class to retrieve its children. The UpdatePanel takes care of creating a XMLHttpRequest object and loading the children asynchronously.
Happy Programming!