简体   繁体   中英

Storage/Usage of a large static Collection

I've searched for answers to this, but cannot find even the slightest bit of definitive advice or information. I should note this is a ASP.Net 4.5.2 webforms application, running on IIS.

TL;DR - How does ASP.Net store large static collections, and are there best practices for searching for specific items?

I have a static collection of objects, that will only be changed during development. During runtime, the collection will never change, and will present the same objects to all users. I am planning to implement as follows:

public class Widget
{
    public Int32 Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string ApiUrl { get; set; }
}

public static class AvailableWidgets
{
    public static List<Widget> LoadWidgets()
    {
        return new List<Widget>()
        {
            new Widget() { Id = 1, Title = "Foo", Description = ".", ApiUrl = "/api/Foo" },
            new Widget() { Id = 2, Title = "Bar", Description = "..", ApiUrl = "/api/Bar" }.
            new Widget() { Id = 3, Title = "FooBar", Description = "...", ApiUrl = "/api/FooBar" }
        };
    }
}

This list may grow to be very large (also there are many more properties, and additional lists as properties of the displayed class). I was going to move this data into SQL Server, but that brings overhead of its own, and also the CRUD code.

I have the following questions:

  1. How does ASP.Net store large static collections? Are these in-memory? What happens if the size of the collection is detrimental to the available memory (does it get placed onto the physical disk)?

  2. If I opt for the above approach, if I need to find a specific item in the collection, eg

    Widget widget1 = (from w in AvailableWidgets.LoadWidgets() where w.Id == 2352 select w).FirstOrDefault();

    ...is it bad practice to retrieve the whole collection first? Are there ways around this?

  3. Likewise, if I only need a specific property value from a single item, is this just awful for a large collection?

    string title = (from w in AvailableWidgets.LoadWidgets() where w.Id == 123 select w).FirstOrDefault().Title;

Any guidance from a seasoned listoholic would be very welcome.

How does ASP.Net store large static collections? Are these in-memory? What happens if the size of the collection is detrimental to the available memory (does it get placed onto the physical disk)?

There is no difference between static fields and any other kind of variables, they are always stored in memory. This means that if your web application takes too much memory it will be handled by the OS (and maybe part of the memory copied into the disk as virtual memory).

If you really need those data to be static, what I would do, as stated in the comments, is to use the correct data types for your collection so you can easily access its members without risking memory leaks for the re-creation of the collection every time it is accessed.

Your AvailableWidgets class could be changed to this:

public static class AvailableWidgets
{
    private static readonly Lazy<Dictionary<int, Widget>> LazyWidgets = new Lazy<Dictionary<int, Widget>>(LoadWidgets);

    public static IEnumerable<Widget> All => LazyWidgets.Value.Values;

    public static Widget GetById(int id)
    {
        Widget widget;
        if (LazyWidgets.Value.TryGetValue(id, out widget))
            return widget;
        return null;
    }

    private static Dictionary<int, Widget> LoadWidgets()
    {
        return new Dictionary<int, Widget>()
        {
            {1, new Widget() {Id = 1, Title = "Foo", Description = ".", ApiUrl = "/api/Foo"}},
            {2, new Widget() {Id = 2, Title = "Bar", Description = "..", ApiUrl = "/api/Bar"}},
            {3, new Widget() {Id = 3, Title = "FooBar", Description = "...", ApiUrl = "/api/FooBar"}}
        };
    }
}

This has many advantages:

  • The Widgets dictionary is initialized only once in the entire application lifetime (when it is accessed for the first time);
  • By using a dictionary internally you can access to single Widgets by id in O(1) (you no longer need to enumerate the collection);
  • If you need to query all the widgets you can do it by using All property, which exposes an IEnumerable interface.

Inside your application you can use it like this:

//single item
var widget = AvailableWidgets.GetById(id);

//single property
var title = widget?.Title;

//query
var matchingWidgets = AvailableWidgets.All.Where(w => w.Title.Contains("Foo"));

Regarding the underlying collection type, you said:

During runtime, the collection will never change, and will present the same objects to all users

Then you will find no benefit in using ConcurrentDictionary , it will only slow down a bit the access to its elements because of its overhead. It could be useful only if you plan to access and then modify (add, remove, change) the collection at runtime by multiple threads.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM