Sunday, March 30, 2014

Task Parallel Library FAIL

Sometimes it inevitable to make mistakes, even Dr. Gregory House loses a patient once a season, the real crime is repeating mistakes.
Today I'm going to teach you how to cure one more fatal disease.
The symptoms:
  • Multi-threaded code is irresponsive.
  • Async operations don’t seem to be Asynchronous.
  • Dead locks.
The problem begins with ‘Task.Factory.StartNew’ and the misconception of how it behaves. The common known behavior would be that it adds an action into the thread pool and executes it eventually. Most of the time, this would be true.
However, when a component does what you expect of it only ‘most of the time’, it’s a recipe for future failures such as slowness and in extreme cases even dead locks which can be extremely expensive when detected in production.

So what really happens when we call Start() for a task?
If we did not set an explicit scheduler, the task would run on its default scheduler, which is in the thread-pool, OR in the current context scheduler.
Current context scheduler? What is that?
It’s an internal property of the TPL framework, containing the scheduler running the current thread. When it exists and we start a new task without explicitly specifying which scheduler the task should use, it will run on the current thread scheduler.

Let's have a look:
This is an example of the issue with dead lock.

var qts = new System.Threading.Tasks.Schedulers.QueuedTaskScheduler(1);
TaskFactory tf = new TaskFactory(qts);
tf.StartNew(() =>
{

 
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
  Task.Factory.StartNew(() => { manualResetEvent.Set(); });
  manualResetEvent.WaitOne();
}).Wait();


Now that we think we understand how things work, let’s make them a little more complicated:

var qts = new System.Threading.Tasks.Schedulers.QueuedTaskScheduler(1);
TaskFactory tf = new TaskFactory(qts);
tf.StartNew(() =>
{
 
 
   Task.Factory.StartNew(() => { }).Wait();
}).Wait();


By the same logic, this code should have been locked for the same reason. But it isn’t.
The reason for that is because the framework holds some “dark magic” behind the scenes.
This “dark magic” is Microsoft’s way of overcoming some of the inheritance problems that are caused by putting advanced tools in the hands of unexperienced programmers. The problem is that black magic doesn’t work with full scale applications. You need to fully understand what’s going on under the hood when writing good code, assuming that you care about quality and not just about your LinkedIn profile.

Don't get me wrong, TPL is great and I will continue using it whenever I can. However, I will never, under no circumstance write this code:
   Task.Factory.StartNew(() => { });
I will use instated:
   new Task(() => { }).Start(TaskScheduler.Default);

Some very complex regex can fix my project, but I rather do it the hard way and fix it manually.
Remember it's not just ‘Task.Factory.StartNew’ it happens in ‘ContinueWith’ as well.

Sunday, March 9, 2014

One small step up




Versioning is always a difficult task. Usually it has some product meaning (Windows 8) and other time it expresses a marketing twist (jellybean).  As programmers, we usually don’t care about corporeal requirements.

.NET give us a basic and simple way to version our assemblies:
[assembly: AssemblyVersion("1.0.0.0")]

Like most of Microsoft infrastructure, we are only given tools that we can utilize and abuse in any way we’d like. Everyone has a different way of versioning components. I'm not going to discuss the theory of versioning, but I recommend reading this excellent article by the Github site founder at http://semver.org/.

So, I am going to talk about how I like to version my files.
I like to increase the build element of the version number whenever an assembly has changed between releases.



Simple rule. Hard to follow?


When there are only two projects in your solution, this rule is easy to follow because it can be manually managed. However, like one of my colleagues always says, “it doesn't scale”. Meaning, I have to manage a hundred projects, there is no way of tracking the changes between releases without a heavy dose of painkillers.

 
Finding excuses why not to do this, is exceptionally easy:
·        It’s easier to increase all the assemblies, like many build servers provide out of the box.
·        It’s also easier to match the executable version to the build counter.
·        Some might even go overboard and use the automatic build version "1.0.*".

 
All of these methods fail to follow the first and only rule – increase your version number whenever an assembly has changed between releases.

In order to follow this rule and avoid excuses, I’ve created a simple utility http://github.com/ronenbarak/Barak.VersionPatcher

This is a simple executable command line that can either be run manually or automatically by the build server. Its functionality is simple. It will search for changes in your source control, analyze your projects and generate the version number. Eventually it will check-in all the changes, all of this completely automatically.


Finally, I removed one more task off the release board (and actually did it right!).

This solution will probably not fit everyone, but if you want to version your files like I do, I’ve already done the heavy lifting for you. Just download the release published on github. If you don't like the way your files are versioned now and you don’t like the way I handled it, feel free to fork my implementation and customize your own.


Happy versioning!