Skip to content

Instantly share code, notes, and snippets.

@anderssonjohan
Last active December 18, 2015 21:48
Show Gist options
  • Save anderssonjohan/5849718 to your computer and use it in GitHub Desktop.
Save anderssonjohan/5849718 to your computer and use it in GitHub Desktop.
Which method is the fastest one of string StartsWith, Substring and IndexOf? (Spoiler: Substring)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace startswithorsubstring
{
class Program
{
const string wsHref = "workspace://oeuoooououoeuouoeuoeu/12312321831283283182328";
const string noWsHref = "cases/12123132";
static Regex regex = new Regex( "workspace://(?<Type>.*)/(?<Name>[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}).*", RegexOptions.Compiled );
public static bool IsWorkspaceUri( string uri )
{
if ( String.IsNullOrEmpty( uri ) )
return false;
Match m = regex.Match( uri );
return m.Success;
}
static readonly Expression<Func<string, bool>> startsWithEx = s => s.StartsWith( "workspace:" );
static readonly Expression<Func<string, bool>> substringEx = s => s.Length > 10 && s.Substring( 0, 10 ) == "workspace:";
static readonly Expression<Func<string, bool>> indexOfEx = s => s.IndexOf( "workspace:", 0 ) != -1;
static readonly Func<string, bool> startsWith = startsWithEx.Compile();
static readonly Func<string, bool> substring = substringEx.Compile();
static readonly Func<string, bool> indexOf = indexOfEx.Compile();
static void Main( string[] args )
{
Console.WriteLine( "ws href: {0} no ws href: {1}", wsHref, noWsHref );
Console.WriteLine( "startswith: {0}", startsWithEx );
Console.WriteLine( "substring: {0}", substringEx );
Console.WriteLine( "indexOf: {0}", indexOfEx );
int rounds;
if ( !( args.Length == 1 && Int32.TryParse( args[0], out rounds ) ) )
{
rounds = 3;
}
foreach ( var round in Enumerable.Range( 1, rounds ) )
{
Console.WriteLine( "Round {0}", round );
RunTest();
}
Console.ReadLine();
}
static void RunTest()
{
var wsStartsWith = ElapsedMs( wsHref, startsWith );
var wsSubstring = ElapsedMs( wsHref, substring );
var wsIndexOf = ElapsedMs( wsHref, indexOf );
var wsRx = ElapsedMs( wsHref, IsWorkspaceUri );
var noWsStartsWith = ElapsedMs( noWsHref, startsWith );
var noWsSubstring = ElapsedMs( noWsHref, substring );
var noWsIndexOf = ElapsedMs( noWsHref, indexOf );
var noWsRx = ElapsedMs( wsHref, IsWorkspaceUri );
Console.WriteLine();
Console.WriteLine( "ws uri" );
Console.WriteLine();
Console.WriteLine("startswith: {0}", wsStartsWith );
Console.WriteLine("substring: {0}", wsSubstring );
Console.WriteLine("indexof: {0}", wsIndexOf );
Console.WriteLine("rx: {0}", wsRx );
Console.WriteLine();
Console.WriteLine( "no ws uri" );
Console.WriteLine();
Console.WriteLine( "startswith: {0}", noWsStartsWith );
Console.WriteLine( "substring: {0}", noWsSubstring );
Console.WriteLine( "indexof: {0}", noWsIndexOf );
Console.WriteLine( "rx: {0}", noWsRx );
Console.WriteLine( "=====" );
}
static double ElapsedMs( string wsHref, Func<string,bool> action )
{
var times = new List<Stopwatch>();
var pelle = 0;
for ( var i = 0; i < 10; i++ )
{
var sw1 = Stopwatch.StartNew();
for ( var j = 0; j < 1000000; j++ )
{
if ( action( wsHref ) )
{
// yay
pelle++;
}
}
sw1.Stop();
times.Add( sw1 );
}
return times.Average( sw => sw.ElapsedMilliseconds );
}
}
}
@anderssonjohan
Copy link
Author

Sample output:

ws href: workspace://oeuoooououoeuouoeuoeu/12312321831283283182328 no ws href: cases/12123132
startswith: s => s.StartsWith("workspace:")
substring: s => ((s.Length > 10) AndAlso (s.Substring(0, 10) == "workspace:"))
indexOf: s => (s.IndexOf("workspace:", 0) != -1)

Round 1
ws uri
startswith: 545,3
substring: 46,1
indexof: 570,7
no ws uri
startswith: 278,6
substring: 41,6
indexof: 1267,9
=====
Round 2
ws uri
startswith: 538,6
substring: 44,8
indexof: 560,2
no ws uri
startswith: 259,9
substring: 39,8
indexof: 1227,5
=====
Round 3
ws uri
startswith: 546,5
substring: 44,1
indexof: 564,9
no ws uri
startswith: 266,1
substring: 40
indexof: 1254,8
=====

@anderssonjohan
Copy link
Author

Added test for existing code being used - using a regex:

ws href: workspace://oeuoooououoeuouoeuoeu/12312321831283283182328 no ws href: cases/12123132
startswith: s => s.StartsWith("workspace:")
substring: s => ((s.Length > 10) AndAlso (s.Substring(0, 10) == "workspace:"))
indexOf: s => (s.IndexOf("workspace:", 0) != -1)
Round 1

ws uri

startswith: 546,9
substring: 45,3
indexof: 567,9
rx: 2970

no ws uri

startswith: 260,2
substring: 39,6
indexof: 1225,8
rx: 2904,3
=====
Round 2

ws uri

startswith: 533,5
substring: 44,6
indexof: 557
rx: 2952,8

no ws uri

startswith: 265,1
substring: 42,1
indexof: 1221,5
rx: 2939,6
=====
Round 3

ws uri

startswith: 532,2
substring: 45,7
indexof: 554,5
rx: 2938,6

no ws uri

startswith: 259,2
substring: 39,9
indexof: 1245,5
rx: 3016,9
=====

@anderssonjohan
Copy link
Author

Fun fact: non-compiled regex takes about 5500ms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment