static void Main(string[] args) { const int sleepDurationInSeconds = 1000; // TaskFactory.StartNew() vs. Task.Run() ActionTimer.Time("TaskFactory.StartNew()", () => { Task factoryTask = Task.Factory.StartNew(() => Task.Delay(sleepDurationInSeconds)); Task.WaitAll(factoryTask); }); ActionTimer.Time("Task.Run()", () => { Task runTask = Task.Run(() => Task.Delay(sleepDurationInSeconds)); Task.WaitAll(runTask); }); // Disclaimer Console.WriteLine(Environment.NewLine + "Disclaimer:" + Environment.NewLine + "TaskFactory.StartNew() runs faster because Task.Run goes through a setup process for async/await. The task returned by TaskFactory.StartNew can not be used with async/await unless unwraped into an asynchronous operation with TaskExtensions.Unwrap()." + Environment.NewLine); // Task Cancellation ActionTimer.Time("Task Cancellation", () => { Console.WriteLine("Starting cancellable task which will run for 60 seconds if not cancelled (cancellation is set to occur after 3 seconds)."); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); Task cancelableTask = Pseudo.LongRunningCancellableTask(cancellationTokenSource.Token); cancellationTokenSource.CancelAfter(3000); cancelableTask.Wait(); }); // Async / Await AsyncAwaitConcepts(); Console.ReadLine(); }
public void ExploratoryTesting_OnPerformance() { var watch = new Stopwatch(); ActionTimer.Time(watch, () => { var c = new WithoutEnsure().NonZero; }, 1000000); long withoutEnsure = watch.ElapsedTicks; Debug.WriteLine("withoutEnsure: " + withoutEnsure); watch.Reset(); ActionTimer.Time(watch, () => { var c = new WithEnsure().NonZero; }, 1000000); long withEnsure = watch.ElapsedTicks; Debug.WriteLine("withEnsure: " + withEnsure); watch.Reset(); ActionTimer.Time(watch, () => { var c = new WithNullable().NonZero; }, 1000000); long withNullable = watch.ElapsedTicks; Debug.WriteLine("withNullable: " + withNullable); Assert.That(withoutEnsure, Is.LessThan(withEnsure).And.LessThan(withNullable), "doing nothing is the fastest, but it does allow a undefined value in the enumeration."); Assert.That(withEnsure, Is.GreaterThan(withNullable), "having a custom method to ensure the defined value is more expensive than using a nullable private field"); }
public void MultipleCallsToInitializer_AreFasterThan_MultipleCallsToProvider() { var provider = new EmbeddedXmlProvider(); TimeSpan providerTime = ActionTimer.Time(() => { foreach (var code in Enumeration.GetValues <CurrencyIsoCode>()) { provider.Get(code); } }); TimeSpan initializerTime = ActionTimer.Time(() => { using (var initializer = new EmbeddedXmlInitializer()) { foreach (var code in Enumeration.GetValues <CurrencyIsoCode>()) { initializer.Get(code); } } }); Assert.That(initializerTime, Is.LessThan(providerTime)); }
static void Main(string[] args) { // Setup int value = 0; const int oneBillion = 1000000000; // Without "lock" synchronization Console.WriteLine("Counting to 1,000,000,000 without locking..."); ActionTimer.Time("Without \"lock\"", () => { Task withoutLockTaskA = Task.Run(() => { while (value < oneBillion) { value++; } }); Task withoutLockTaskB = Task.Run(() => { while (value < oneBillion) { Thread.Sleep(1); value++; } }); Task.WaitAll(withoutLockTaskA, withoutLockTaskB); }, false); Console.WriteLine("Computed value: " + value.ToString("N0")); Console.WriteLine(value != oneBillion ? "(Incorrect value was produced due to race conditions)" : "(Correct value was produced... Try running it again)"); Console.WriteLine(); // Keyword: "lock" synchronization Console.WriteLine("Counting to 1,000,000,000 using keyword \"lock\" for synchronization..."); value = 0; object keywordLockObject = new object(); ActionTimer.Time("Keyword \"lock\" synchronization", () => { Task withLockTaskA = Task.Run(() => { while (true) { lock (keywordLockObject) { if (value < oneBillion) { value++; } else { break; } } } }); Task withLockTaskB = Task.Run(() => { while (true) { Thread.Sleep(1); lock (keywordLockObject) { if (value < oneBillion) { value++; } else { break; } } } }); Task.WaitAll(withLockTaskA, withLockTaskB); }, false); Console.WriteLine("Computed value: " + value.ToString("N0")); Console.WriteLine(value != oneBillion ? "(Incorrect value was produced due to race conditions) [This message will never show]" : "(Correct value was produced)"); Console.WriteLine(); // Monitor equivalent of "lock" keyword Console.WriteLine("Counting to 1,000,000,000 using a monitor (lock equivalent) for synchronization."); value = 0; object monitorLockObject = new object(); ActionTimer.Time("Monitor equivalent of \"lock\" keyword", () => { Task withMonitorTaskA = Task.Run(() => { while (true) { bool lockTaken = false; try { Monitor.Enter(monitorLockObject, ref lockTaken); if (value < oneBillion) { value++; } else { break; } } finally { if (lockTaken) { Monitor.Exit(monitorLockObject); } } } }); Task withMonitorTaskB = Task.Run(() => { while (true) { Thread.Sleep(1); bool lockTaken = false; try { Monitor.Enter(monitorLockObject, ref lockTaken); if (value < oneBillion) { value++; } else { break; } } finally { if (lockTaken) { Monitor.Exit(monitorLockObject); } } } }); Task.WaitAll(withMonitorTaskA, withMonitorTaskB); }); Console.WriteLine("Computed value: " + value.ToString("N0")); Console.WriteLine(value != oneBillion ? "(Incorrect value was produced due to race conditions) [This message will never show]" : "(Correct value was produced)"); Console.WriteLine(); Console.ReadLine(); }
static void Main(string[] args) { // Setup int iterations = 10; Console.WriteLine("Starting... "); // Non-Parallel ActionTimer.Time("Non-Parallel", () => { for (int i = 0; i < iterations; i++) { Pseudo.LongRunningAction().Invoke(); } }); // Parallel.For ActionTimer.Time("Parallel.For", () => Parallel.For(0, iterations, Pseudo.LongRunningActionInt())); // Parallel.Foreach ActionTimer.Time("Parallel.ForEach", () => Parallel.ForEach(Enumerable.Range(0, iterations), Pseudo.LongRunningActionInt())); // Parallel.Invoke Action[] iterationActions = new Action[iterations]; for (int i = 0; i < iterationActions.Length; i++) { iterationActions[i] = Pseudo.LongRunningAction(); } ActionTimer.Time("Parallel.Invoke", () => Parallel.Invoke(iterationActions)); // Other Parallel method overloads ActionTimer.Time("Parallel.Foreach overload using the TLocal variable and TLocal finalizer (time has significance for this example)", () => { const int maxRange = 100000; int totalBytes = 0; Random random = new Random(); Parallel.ForEach(Enumerable.Range(0, random.Next(maxRange / 2, maxRange)), () => 0, (integer, loopState, threadLocalSubtotal) => { return(threadLocalSubtotal + BitConverter.GetBytes(integer).Length); }, (threadLocalSubtotal) => { Interlocked.Add(ref totalBytes, threadLocalSubtotal); }); }); ActionTimer.Time("Parallel.Invoke", () => Parallel.Invoke(iterationActions)); // P-LINQ Setup iterations = 100000; List <int> dataSet = Enumerable.Range(1, iterations).ToList(); // LINQ (Non-Parallelized) Method Syntax ActionTimer.Time("LINQ (Non-Parallelized) Method Syntax", () => dataSet.Where(value => value % 2 == 0).ToList()); // LINQ (Non-Parallelized) Query Syntax ActionTimer.Time("LINQ (Non-Parallelized) Query Syntax", () => { (from value in dataSet where value % 2 == 0 select value).ToList(); }); // P-LINQ Method Syntax ActionTimer.Time("P-LINQ Method Syntax", () => dataSet.AsParallel().Where(value => value % 2 == 0).ToList()); // P-LINQ Query Syntax ActionTimer.Time("P-LINQ Query Syntax", () => (from value in dataSet.AsParallel() where value % 2 == 0 select value).ToList() ); // LINQ ForEach ActionTimer.Time("LINQ ForEach", () => dataSet.ForEach((value) => { value = value / 2; })); // P-LINQ ForAll ActionTimer.Time("P-LINQ ForAll", () => dataSet.AsParallel().ForAll((value) => { value = value / 2; })); // Disclaimer Console.WriteLine(Environment.NewLine + "Disclaimer:" + Environment.NewLine + "Subsequent Parallel method calls may run faster due to memory caching."); Console.ReadLine(); }
static void Main(string[] args) { // NOTE: The "ToList()" calls below are intentional for to immediately execute the otherwise deffered execution of the query for the sake of being able to use the "ForEach" extension of the IEnumerable interface to reduce output code. // Setup List <Pseudo.StateCityData> pseudoData = Pseudo.GetPseudoStateCityData(); List <Pseudo.CityData> pseudoCityData = Pseudo.GetPseudoCityData(); List <Pseudo.StateData> pseudoStateData = Pseudo.GetPseudoStateData(); Console.WriteLine("Pseudo Data:"); pseudoData.ForEach(data => Console.WriteLine(data.State + " " + data.City)); Console.WriteLine(); // SelectMany Console.WriteLine("SelectMany Method:"); byte[] allCityBytes = pseudoData.SelectMany(data => Encoding.UTF8.GetBytes(data.City)).ToArray(); Console.WriteLine(Encoding.UTF8.GetString(allCityBytes)); Console.WriteLine(); // Projection Example 1 - Method Syntax Console.WriteLine("Projected City Data - Method Syntax:"); var pseudoCityDataCollection = pseudoData.Select(data => data.City); pseudoCityDataCollection.ToList().ForEach(cityData => Console.WriteLine(cityData)); Console.WriteLine(); // Projection Example 1 - Query Syntax Console.WriteLine("Projected City Data - Query Syntax:"); var pseudoCityDataQuerySyntax = (from data in pseudoData select data.City); pseudoCityDataQuerySyntax.ToList().ForEach(cityData => Console.WriteLine(cityData)); Console.WriteLine(); // Projection Example 2 - Method Syntax (Anonymous Type Projection) Console.WriteLine("Projected Anonymous State & City Data - Method Syntax:"); var pseudoStateCityDataCollection = pseudoData.Select(data => new { CityAndState = data.City + ", " + data.State }); pseudoStateCityDataCollection.ToList().ForEach(data => Console.WriteLine(data.CityAndState)); Console.WriteLine(); // Projection Example 2 - Query Syntax (Anonymous Type Projection) Console.WriteLine("Projected Anonymous State & City Data - Query Syntax:"); var pseudoStateCityDataCollectionQuerySyntax = (from data in pseudoData select new { CityAndState = data.City + ", " + data.State }); pseudoStateCityDataCollectionQuerySyntax.ToList().ForEach(data => Console.WriteLine(data.CityAndState)); Console.WriteLine(); // Orderby Clause - Method Syntax Console.WriteLine("OrderBy - Method Syntax:"); var pseudoOrderByCity = pseudoData.OrderBy(data => data.City).Select(data => data.City); pseudoOrderByCity.ToList().ForEach(data => Console.WriteLine(data)); Console.WriteLine(); // Orderby Clause - Query Syntax Console.WriteLine("OrderBy - Query Syntax:"); var pseudoOrderByCityQuerySyntax = from data in pseudoData orderby data.City ascending select data.City; pseudoOrderByCityQuerySyntax.ToList().ForEach(data => Console.WriteLine(data)); Console.WriteLine(); // Group Clause - Method Syntax Console.WriteLine("Group - Method Syntax:"); var pseudoCityStateGroup = pseudoData.GroupBy(data => data.City[0]); pseudoCityStateGroup.ToList().ForEach(displayGroupData); // Group Clause - Query Syntax Console.WriteLine("Group - Query Syntax:"); var pseudoCityStateGroupQuerySyntax = from data in pseudoData group data by data.City[0]; pseudoCityStateGroupQuerySyntax.ToList().ForEach(displayGroupData); // Join Clause - Method Syntax Console.WriteLine("Join - Method Syntax:"); var pseudoCityStateJoin = pseudoCityData.Join(pseudoStateData, cityData => cityData.StateId, stateData => stateData.StateId, (cityData, stateData) => new { CityAndState = cityData.City + ", " + stateData.State }); pseudoCityStateJoin.ToList().ForEach(data => Console.WriteLine(data.CityAndState)); Console.WriteLine(); // Join Clause - Query Syntax Console.WriteLine("Join - Query Syntax:"); var pseudoCityStateJoinQuerySyntax = from cityData in pseudoCityData join stateData in pseudoStateData on cityData.StateId equals stateData.StateId select new { CityAndState = cityData.City + ", " + stateData.State }; pseudoCityStateJoinQuerySyntax.ToList().ForEach(data => Console.WriteLine(data.CityAndState)); Console.WriteLine(); // Let Clause // NOTE: Could just write "from data in pseudoData select cityInReverse"... "Let" is more useful when the result needs to be used in a subsequent "from" clauses (i.e. from using String.Split()). Console.WriteLine("Let Clause - Cities in Reverse:"); var letClauseQuery = from data in pseudoData let cityInReverse = data.City.Reverse() select cityInReverse; letClauseQuery.ToList().ForEach(cityInReverse => Console.WriteLine(cityInReverse.ToArray())); Console.WriteLine(); // Deffered Query Execution int iterations = 100000; Console.WriteLine("Deffered Query Execution - Query does not execute until it is enumerated:"); ActionTimer.Time("Declaring The Query", () => { for (int i = 0; i < iterations; i++) { var defferedExecutionAnonymousScope = from data in pseudoData group data by data.City into g orderby g.Key ascending select g; } }); var defferedExecution = from data in pseudoData group data by data.City into g orderby g.Key ascending select g; ActionTimer.Time("Executing the Query", () => { for (int i = 0; i < iterations; i++) { // NOTE: Compiler might optimize this out... If it does, save it to a non-anonymously scoped List<IGrouping<string, Pseudo.StateCityData>> variable and display it so the enumeration is actually used. defferedExecution.ToList(); } }); Console.ReadLine(); }