uap-csharp icon indicating copy to clipboard operation
uap-csharp copied to clipboard

Significant performance issue when Parser.GetDefault() is called repeatedly

Open codinglifestyle opened this issue 3 months ago • 0 comments

I’ve encountered a significant performance issue with UAParser when it’s used in a logger. The issue arises when Parser.GetDefault() is called repeatedly during large operations. Each call to the logger creates a new instance of the Parser, which leads to a significant performance penalty.

Here’s a simplified test case that demonstrates the issue:

C#

using System;
using System.Diagnostics;
using UAParser;

class Program
{
    const int NumTests = 100;

    static void Main()
    {
        string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3";

        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < NumTests; i++)
        {
            var parser = Parser.GetDefault();
            var clientInfo = parser.Parse(userAgent);
        }
        stopwatch.Stop();
        Console.WriteLine($"Test Case 1 elapsed time: {stopwatch.ElapsedMilliseconds} ms");

        stopwatch.Restart();
        var parserOutsideLoop = Parser.GetDefault();
        for (int i = 0; i < NumTests; i++)
        {
            var clientInfo = parserOutsideLoop.Parse(userAgent);
        }
        stopwatch.Stop();
        Console.WriteLine($"Test Case 2 elapsed time: {stopwatch.ElapsedMilliseconds} ms");
    }
}

In Test Case 1, Parser.GetDefault() is called 100 times, leading to a total elapsed time of 4046 ms. In Test Case 2, Parser.GetDefault() is called only once, and the same instance is used for all iterations of the loop, resulting in a total elapsed time of 190 ms.

Test Case 1 elapsed time: 4046 ms Test Case 2 elapsed time: 190 ms

This demonstrates that the time taken to instantiate the Parser object with Parser.GetDefault() is quite significant. It seems that the regex patterns are loaded from the assembly each time Parser.GetDefault() is called.

The actual fix was to instantiate the Parser as a member variable of the logger class, so it’s created only once and reused for all subsequent calls to the logger.

I couldn’t find any explicit warnings or notes about this in the UAParser documentation. It would be helpful if the documentation could provide some guidance or warning about this so others don't repeat the same bug.

codinglifestyle avatar Mar 29 '24 13:03 codinglifestyle