Thursday 21 September 2017

TObjectList vs TObjectDictionary

When I need to store a list of objects I usually use a TObjectList (Generics.Collections), but I was speaking to another developer who uses TObjectDictionary to store a list of objects. I searched the net for when to use a TObjectDictionary instead of a TObjectList and vice-versa, but could not find any definitive answers. I decided to write a little test app to understand the difference, this simply did the following:

  • Created 1 million objects for each list and added them to the list.
  • Cleared the list of the 1 million objects.
  • Populated the list with 1 million newly created objects.
  • Found 100 objects in the list.
Below are the results, time is in ms:


ObjectList Clear - 47
ObjectList Populate - 344
ObjectList Find - 78
ObjectList Find - 78
ObjectList Find - 78
ObjectList Find - 79

ObjectDictionary Clear - 265
ObjectDictionary Populate - 579
ObjectDictionary Find - 0
ObjectDictionary Find - 0
ObjectDictionary Find - 0
ObjectDictionary Find - 0

As you can see the TObjectDictionary was slower to clear and populate the list, but was faster finding the 100 objects. This is most likely due to the TObjectDictionary being derived from TDictionary which is a hash table and is optimised for lookups.

So, generally from these results I am happy sticking with TObjectList, but if I need to store a lot of objects and also need to find a lot of objects then using a TObjectDictionary is a better choice. 

5 comments:

  1. You are probably using the wrong class anyway. The generic TObjectList is slow as a turtle, compared to the old and good TObjectList which descends from TList. It is not only slow, but also bloated. Add to that the fact that TList and TObjectList can also be improved if you implement them yourself.
    If you are just holding a few objects in a desktop application, then it won't matter much. What amazes me is the number of libraries and frameworks out there supposed to work on "server" side applications, using this abomination. Here is the bug report: https://quality.embarcadero.com/browse/RSP-18815

    ReplyDelete
    Replies
    1. Oh my - you are comparing a class that can JUST store pointers (ot things hardcasted to pointers) which one that can contain ANYTHING. Yes, of course it has some overhead (mainly for the possible OnChange notification built into it and second for the comparer being used because its a generic type and cannot just do a pointer compare).

      It could however use an optimized version inside the IndexOf that uses a plain pointer compare when T is a pointer. But hey, if you just storing pointers then feel free to use TList if the performance matters to you.

      As for using TList in the RTL that is because that code needs to run also under ARC and using pointers would not work there because the list would not hold a strong reference then.

      Comparing code that takes 4ms vs 7ms in a tight loop is nonsense anyway since that is hardly anything that affects a real world application to that degree.

      Delete
    2. I think you didn't read the bug report. I'm comparing a code that runs in 1442 ms against a similar code that runs in 15200 ms, 11 times slower. If you are convinced that this is not important, you should hurry up and notify Embarcadero that they shouldn't spend time on it. I guess they "mistakenly" marked that as "Major" priority...

      Delete
    3. I think you didn't my comment - I said the IndexOf method could be optimized. The question is rather if that performance test of yours really matters if you are just measuring one method in isolation which hardly is any real world scenario.

      So the question is how that actually compares in reality and if it really affects a real world applications speed noticeably.

      I am not saying that RTL code should be as fast as it could (it should and there are many more pieces that are unnecessarily taking more time than they have to) - but you are overreacting about this particular thing.

      Delete
  2. Gotta admit, ive never heard of TObjectDictionary. Only ever used TObjectList, TList is easy as well, but sometimes you'll forget to remove things.

    ReplyDelete