Starting to introduce use of the Async Await pattern on an established codebase can pose challenges which don't exist when using Async on a new project. If the code already makes use of background threads which do Thread.Sleep(), when you change to using Async methods, make sure you switch from Thread.Sleep() to await Task.Delay() instead. This achieves the same result of suspending that bit of work, but does it in a nonblocking way which can reduce the total resources needed by the application.
Friday, 30 October 2015
Thursday, 29 October 2015
ASP.NET Tips #42 - Remember that different ways of reading large files have different performance characteristics
Using File.ReadAllBytes() can sometimes be faster than reading a stream obtained by opening a large file such as XML. This can be influenced by factors like whether you need to access all of a file or just a small portion of it. If in doubt, use a tool like Telerik JustTrace or ANTS Performance Profiler to measure the impact of different methods of file access.
Wednesday, 28 October 2015
ASP.NET Tips #41 - Concurrent asynchronous I/O on server applications
Concurrent I/O operations on server applications are tricky and hard to handle correctly. This is especially the case when applications are under high load. I would like to highlight two core principals to keep in mind:
Firstly, never perform concurrent I/O operations in a blocking fashion on your .NET server applications. Instead, perform then asynchronously, like the following code snippet:
[HttpGet] public async Task<IEnumerable<Car>> AllCarsInParallelNonBlockingAsync() { IEnumerable<Task<IEnumerable<Car>>> allTasks = PayloadSources.Select(uri => GetCarsAsync(uri)); IEnumerable<Car>[] allResults = await Task.WhenAll(allTasks); return allResults.SelectMany(cars => cars); }
When concurrent requests are made, the asynchronous method typically performs six times faster.
Secondly, remember to also perform load tests against your server applications based on your estimated consumption rates if you have any sort of multiple I/O operations.
For more information, see http://www.tugberkugurlu.com/archive/how-and-where-concurrent-asynchronous-io-with-asp-net-web-api
Tuesday, 27 October 2015
ASP.NET Tips #40 - Fully utilize all bottlenecks
While Async-Await habits work well, an architectural pattern can switch into higher gears. When processing multiple small jobs, consider splitting job parts into resource-specific chunks. Then create separate threads for each resource, and place memory buffers in between. The goal is to fully utilize whatever resource is the bottleneck on any given machine.
In the diagram below, for example, an application has four steps. It first reads a file from disk, does some processing on it, stores results in a database, and finally deletes the file. Each red box is a separate thread, and each vertical ‘swim-lane’ represents a particular resource. The process flows from top to bottom and uses queues as buffers between each resource-switch.
Sunday, 25 October 2015
ASP.NET Tips #39 - Before optimizing code, profile the app so that you know where bottlenecks are
This is something that is said in many places but I want to repeat it once again because it's so important. Even using the new profiling tools in Visual Studio 2015 to analyze performance issues in your application will help. With an expert profiling tool like Telerik JustTrace or ANTS Performance Profiler, you'll find out a lot more about the bottlenecks that are there – and be able to do a lot more, a lot faster.
Friday, 23 October 2015
ASP.NET Tips #38 - Prepare performance optimization projects in advance
Good performance optimization projects need appropriate preparation in four key areas:
- Create a test environment where you can reproduce consistent performance behavior. Ideally, you want an automated test that shows equal performance if you run it multiple times. Don't start optimizing without such a test environment.
- Measure performance KPIs before you change anything to serve as a benchmark. Compare the performance against the benchmark after changing the code. If the changes make the code faster, the new test results are your new benchmark. If not, undo the changes and continue to analyze with a profiler tool.
- Don't change too much at the same time. Make small changes, measure, and decide if you want to keep your change. If you make multiple changes, one change can make your code faster, while the other one might destroy the positive effects.
- Never guess, measure it! Get a profiler and use it to spot performance bottlenecks. In many cases, performance killers are where you don't expect them. Avoid optimizing code just because you have the feeling that it does not perform well.
Thursday, 22 October 2015
ASP.NET Tips #37 - Assume .NET problems are your fault, unless you have evidence to the contrary
It's tempting to blame system code, third party libraries, or even the .NET framework itself when there's a problem. But it's almost always the case that your application is misusing other people's code, so make sure you have really good evidence that a problem is elsewhere before blaming someone else.
Besides that, there are some common mistakes that unavoidable:
- Create new ASP.NET 4.5 VS project, but still reusing some .NET 2.0 class library (other people's code) which is not fully optimized for .NET 4.5 environment.
- Compiled VS project in 32-bit platform, but deploy and execute on 64-bit IIS Server. If you really want to use 32-bit 3rd party component libraries, always remember to set "Enabled 32-Bit Applications" to TRUE in IIS AppPool.
- About best practices, always use 64-bit 3rd party components (supported async/await) in any VS Project (Platform: Any CPU) during DEV -> UAT -> PROD stage to achieve great system performance and maximize server resources utilization.
Tuesday, 20 October 2015
ASP.NET Tips #36 - Perception is king
If you can't do everything quickly, sometimes it's enough just to make a user think you're quick.
From a user's perspective, the most important time is often the delay until they can see something useful on a page, rather than every single detail being available. For example, if serving up a Tweet button adds 200ms to a page's load time, consider using ajax to load the button asynchronously after the more important content is available.
This principle applies to desktop apps too. Ensuring that long running tasks are done off the UI thread avoids the impression that an application has "locked up", even if an action takes the same length of time to complete. Techniques like spinnies and progress indicators also have a role to play here, letting the user feel as though progress is being made.
Monday, 19 October 2015
ASP.NET Tips #35 - Use defensive coding techniques such as performing null checks wherever applicable to avoid NullReferenceExceptions at runtime
Exceptions can be slow and should only be used in exceptional circumstances, rather than for general control flow. Instead of assuming an object will not be null at runtime, utilize defensive coding to ensure your code only acts on objects that are not null. This will assist performance by throwing fewer exceptions, and ensure a more robust and reliable application.
For example, consider the Tester-Doer pattern explained here: https://msdn.microsoft.com/en-us/library/vstudio/ms229009(v=vs.100).aspx
Tuesday, 13 October 2015
ASP.NET Tips #34 - Consider String.Replace() for parsing, trimming, and replacing
String.Replace() can be a good choice, particularly for individual case-sensitive replacements where it outperforms other algorithms. String Split/Join and String Split/Concat perform equally, while LINQ and RegEx have poor performance for parsing, trimming, and replacing.
For more information, see: http://blogs.msdn.com/b/debuggingtoolbox/archive/2008/04/02/comparing-regex-replace-string-replace-and-stringbuilder-replace-which-has-better-performance.aspx
Monday, 12 October 2015
ASP.NET Tips #33 - If you must measure small time differences in your code, ensure you use the StopWatch class
using System.Diagnostics; class Program { static void Main(string[] args) { Stopwatch sw = Stopwatch.StartNew(); // Do something here sw.Stop(); Console.WriteLine("Elapsed time: " + sw.Elapsed.ToString()); } }