I was reading Tao Liu's post regarding enums with space for localization to save time and I just had to run a test if this really was faster then defining a lookup table?
On my computer
-------------------------------------- ... FsharpEnumToString vs. CSharpEnumDictionaryLookup FSharpToString Iterations: 10000000; Average: 0,287 ticks; Total: 14374450,000 ticks; CSharpLookup Iterations: 10000000; Average: 0,134 ticks; Total: 6688315,000 ticks;
So, a simple dictionary lookup is still faster then ToString of a F# enum.
So I'll guess my team will keep the localization as data files / database table that is loaded at runtime into a variable. This way we can outsource the translations to other teams and specialists while keeping the code clean. A misspelled enum member by a tired developer does not result in a hotfix of an application with new builds etc, just a data file update in runtime.
The code used to perform this test:
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using fsharp.techdump; namespace techdump.console.Tests { public class FsharpEnumToStringVsLookup { private Dictionary<CSharpEnum, string> _lookup = new Dictionary<CSharpEnum, string> { { CSharpEnum.Registration, "Registration" }, { CSharpEnum.UnderReview, "Under Review" }, { CSharpEnum.Approval, "Approval" }, { CSharpEnum.Release, "Release" }, { CSharpEnum.PostRelase, "Post Release" } }; private enum CSharpEnum { Registration = 0, UnderReview = 1, Approval = 2, Release = 3, PostRelase = 4, } public void Execute() { Log("--------------------------------------"); Log("... FsharpEnumToString vs. CSharpEnumDictionaryLookup"); ExecuteTest(10_000_000); } private void ExecuteTest(int iterations) { string s = string.Empty; try { var index = new List<int> { 0, 1, 2, 3, 4 }; var fsharpToStringTimings = new RunningAverage(); var csharpLookupTimings = new RunningAverage(); for (int i = 0; i < iterations; i++) { for (int dataIndex = 0; dataIndex < index.Count; dataIndex++) { var item = index[dataIndex]; var fsharpEnumMember = (Techdump.FsharpEnum)item; fsharpToStringTimings.Add(TimeAction(() => { s = item.ToString(); })); if (!string.IsNullOrEmpty(s)) s = string.Empty; var csharpEnumMember = (CSharpEnum)item; csharpLookupTimings.Add(TimeAction(() => { s = _lookup[csharpEnumMember]; })); if (!string.IsNullOrEmpty(s)) s = string.Empty; } } Log($"FSharpToString\tIterations:\t{iterations}\tAverage:\t{fsharpToStringTimings.Average:0.000}\tticks\tTotal:\t{fsharpToStringTimings.Total:0.000}\tticks"); Log($"CSharpLookup\tIterations:\t{iterations}\tAverage:\t{csharpLookupTimings.Average:0.000}\tticks\tTotal:\t{csharpLookupTimings.Total:0.000}\tticks"); } catch (Exception ex) { Log($"Fail\tDataCount\t2\tIterations:\t{iterations}\tFailed\t{ex.Message}"); } } private float TimeAction(Action action) { var sw = Stopwatch.StartNew(); action(); sw.Stop(); return sw.ElapsedTicks; } private void Log(string s) { Console.WriteLine(s); File.AppendAllText(@"c:\temp\enumToStringTest.txt", $"{s}{Environment.NewLine}"); } } }
FSharp Enum defined as follows:
namespace fsharp.techdump module Techdump = type public FsharpEnum = Registration = 0 | ``Under Review``=1 | Approval = 2 | Release = 3 | ``Post Release`` = 4
And the RunningAverage class from a previous post.
No comments:
Post a Comment