Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

142
Views
Weird performance behavior of .NET dictionary insertion

I have two dictionaries with different value types: Dictionary<int, string[]> and Dictionary<int, int[]>. Suppose we generate random arrays in a loop and insert them to the dictionaries (in C#).

var d1 = new Dictionary<int, string[]>();
var d2 = new Dictionary<int, int[]>();
var sw = Stopwatch.StartNew();
for (int i = 0; i < 40000000; i++)
{
    string[] sarr = new string[10];
    for (int j = 0; j < 10; j++)
    {
        sarr[j] = j.ToString();
    }
    int[] iarr = new int[10];
    for (int j = 0; j < 10; j++)
    {
        iarr[j] = j;
    }
    d1[i] = sarr; // (1)
    d2[i] = iarr; // (2)
}
sw.Stop();

Note the last two lines of the for loop. When I run the above code, it takes about 13.9 sec on my machine. Now, when I comment out only (1), then it takes about 13.7 sec. And if I comment out only (2), then it takes about 20 sec. In other words, by removing (2) it becomes much slower! I repeated this multiple times, and I can confirm that the behavior is consistent.

Can anyone please explain how this is even possible?

I did this experiment because I noticed that inserting string[] is slower than inserting int[] even though I am using the same key in the two dictionaries. I would like to know why inserting string [] can be slower than inserting int[], too.

So my quetion is twofold: (1) how come removing a line from the above code can make things slower, (2) why inserting string[] is slower than inserting int[]?


FYI, I am using the latest .NET 5 (5.0.103). I tried the code on both Windows and Linux, and the behavior was the same. I consistently see the same problem using either debug or release mode.


When I diff ILs of commented out version vs. original, the commented out version has no call to set_Item function of the dictionary as expected. Other things are more or less the same.

IL_0079: ldloc.1      // dictionary2
IL_007a: ldloc.3      // key
IL_007b: ldloc.s      numArray
IL_007d: callvirt     instance void class [System.Collections]System.Collections.Generic.Dictionary`2<int32, int32[]>::set_Item(!0/*int32*/, !1/*int32[]*/)
IL_0082: nop

The above part was removed when I commented out (2) for example.


To help repro this problem, I created a simple repo with Benchmark.NET: https://github.com/sangkilc/TestDictionary. In this repo, I reduced the number of iterations (from 40M to 4M) because it takes too long.

On my machine the results are:

.NET Core SDK=5.0.103
  [Host]     : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
  DefaultJob : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT


|   Method |    Mean |    Error |   StdDev |
|--------- |--------:|---------:|---------:|
| TestBoth | 1.269 s | 0.0222 s | 0.0208 s |
|  TestOne | 1.381 s | 0.0257 s | 0.0241 s |

As per @TheodorZoulias's observation, if I modify d2 to a 2D array, then the difference becomes more significant:

|   Method |    Mean |    Error |   StdDev |
|--------- |--------:|---------:|---------:|
| TestBoth | 1.137 s | 0.0195 s | 0.0163 s |
|  TestOne | 1.373 s | 0.0246 s | 0.0345 s |
over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

This is not an answer, just wanted to show off some pictures

I have the code compiled in Release for two of your scenarios:

  • With both (1) and (2)
  • With (1) only

Note that I removed Stopwatch related code, because we're only interested in Dictionary.

I have dotTrace on my machine, so I got some profiling results (line-by-line).

For the both scenario:

By Thread Tree: enter image description here

By Methods: enter image description here

For the (1) only scenario:

By Thread Tree: enter image description here

By Methods: enter image description here

Since you mentioned that the pattern is consistent, I ran the profiling only once.

From the results, we could tell functions related to Dictionary are not the main contributors to the so called "weird performance behavior", GC probably is.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!