Skip to content

Commit

Permalink
Use .ToCharArray() instead of .ToArray() on string
Browse files Browse the repository at this point in the history
The former is preferable performance-wise.
See https://stackoverflow.com/a/37139124
  • Loading branch information
aradalvand committed Sep 13, 2023
1 parent a91b293 commit 7b6be39
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion src/Sqids/SqidsEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public SqidsEncoder(SqidsOptions options)
);
_blockList = options.BlockList.ToArray(); // NOTE: Arrays are faster to iterate than HashSets, so we construct an array here.

_alphabet = options.Alphabet.ToArray();
_alphabet = options.Alphabet.ToCharArray();
ConsistentShuffle(_alphabet);
}

Expand Down

1 comment on commit 7b6be39

@LeaFrock
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, I like the pursuit of performance!

The stackoverflow answer is from 2016 and the source codes have changed a lot since .NET 5.

ToCharArray is absolutely faster. Further speaking, we could import some benchmarks to make perf-improvement more convincing if possible.

Also, I suggest that do NOT use LINQ for hot path codes.

Another example is Encode(params int[] numbers), which could be a hot path if users encode multiple numbers.

The following is my benchmarks for .NET 6/7 based on BenchmarkDotNet.

BenchmarkDotNet v0.13.8, Windows 10 (10.0.19045.3448/22H2/2022Update)
Intel Core i7-8700 CPU 3.20GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 7.0.401
  [Host]   : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2
  .NET 6.0 : .NET 6.0.22 (6.0.2223.42425), X64 RyuJIT AVX2
  .NET 7.0 : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2


| Method | Job      | Runtime  | N  | Mean        | Error     | StdDev    | Ratio | RatioSD | Gen0   | Allocated | Alloc Ratio |
|------- |--------- |--------- |--- |------------:|----------:|----------:|------:|--------:|-------:|----------:|------------:|
| Any    | .NET 6.0 | .NET 6.0 | 2  |  22.1193 ns | 0.2554 ns | 0.2389 ns | 21.09 |    0.19 | 0.0051 |      32 B |          NA |
| Exists | .NET 6.0 | .NET 6.0 | 2  |   6.9775 ns | 0.0986 ns | 0.0874 ns |  6.68 |    0.10 |      - |         - |          NA |
| For    | .NET 6.0 | .NET 6.0 | 2  |   1.0465 ns | 0.0048 ns | 0.0038 ns |  1.00 |    0.00 |      - |         - |          NA |
| Any    | .NET 7.0 | .NET 7.0 | 2  |  20.9733 ns | 0.4390 ns | 0.4312 ns | 19.96 |    0.38 | 0.0051 |      32 B |          NA |
| Exists | .NET 7.0 | .NET 7.0 | 2  |   5.8321 ns | 0.0228 ns | 0.0203 ns |  5.57 |    0.02 |      - |         - |          NA |
| For    | .NET 7.0 | .NET 7.0 | 2  |   0.6355 ns | 0.0370 ns | 0.0346 ns |  0.61 |    0.03 |      - |         - |          NA |
|        |          |          |    |             |           |           |       |         |        |           |             |
| Any    | .NET 6.0 | .NET 6.0 | 20 | 122.5144 ns | 0.2884 ns | 0.2251 ns | 11.59 |    0.07 | 0.0050 |      32 B |          NA |
| Exists | .NET 6.0 | .NET 6.0 | 20 |  46.1017 ns | 0.5632 ns | 0.4993 ns |  4.36 |    0.05 |      - |         - |          NA |
| For    | .NET 6.0 | .NET 6.0 | 20 |  10.5707 ns | 0.0805 ns | 0.0714 ns |  1.00 |    0.00 |      - |         - |          NA |
| Any    | .NET 7.0 | .NET 7.0 | 20 | 113.2418 ns | 0.3804 ns | 0.3177 ns | 10.72 |    0.07 | 0.0050 |      32 B |          NA |
| Exists | .NET 7.0 | .NET 7.0 | 20 |  35.3711 ns | 0.0684 ns | 0.0571 ns |  3.35 |    0.02 |      - |         - |          NA |
| For    | .NET 7.0 | .NET 7.0 | 20 |   9.3445 ns | 0.1372 ns | 0.1146 ns |  0.88 |    0.01 |      - |         - |          NA |

The source codes are below.

[SimpleJob(RuntimeMoniker.Net60, baseline: true)]
[SimpleJob(RuntimeMoniker.Net70)]
[MemoryDiagnoser]
public class AnyVsExists
{
    private int[] numbers = Array.Empty<int>();

    [Params(2, 20)]
    public int N;

    [GlobalSetup]
    public void Setup()
    {
        numbers = Enumerable.Range(0, N).ToArray();
    }

    [Benchmark]
    public bool Any() => numbers.Any(n => n < 0);

    [Benchmark]
    public bool Exists() => Array.Exists(numbers, n => n < 0);

    [Benchmark(Baseline = true)]
    public bool For()
    {
        for (int i = 0; i < numbers.Length; i++)
        {
            if (numbers[i] < 0)
            {
                return true;
            }
        }
        return false;
    }
}

Please sign in to comment.