After nearly two weeks of diversions and delays (mainly related to a BI product release we’ve been working on for a while) I’m back to the Windows Forms application I’ve been doing some work on. A lot of the operations either call out to back-end services and/or databases, or just take a long time – so I’m having to do quite a bit of asynchronous programming. I knew this when I started the project so I read up on synchronisation and multithreading in .NET, yet once again have managed to avoid writing a single line of thread-based code or messing about with synchronisation domains.
Instead I have pretty much exclusively used the BackgroundWorker component. By adopting an event-based model for my components it has been possible to write robust code that doesn’t bring the UI to a standstill and avoids me having to think too hard. In similar exercises during past developments I have used the delegate-based asynchronous event model exposed by WCF and ASMX web service proxies. I suddenly realised that I’ve never actually written threading code – ever (switching the locale using static Thread methods doesn’t count). This isn’t because I don’t understand it, but there are so many cleaner abstractions that exist on top of it that I’ve never had cause to.
I particularly like the BackgroundWorker because of its simplicity and elegance. There are times when it’s not appropriate (such as when you may want to invoke the same method multiple times on different threads), but for applications where the UI is the client context it insulates the developer against the more common problems and errors of synchronisation and concurrency. The fact that it can only run one operation at a time (and will let you know via the IsBusy property) is a boon for preventing unwanted recursion. It also places limitations on how one can access objects in the host context, thus forcing the developer down the ‘right’ road. I think this is a good thing because while it’s beneficial to understand about the Windows message loop, synchronisation contexts, and .NET app domains – it shouldn’t be essential for writing applications where the UI doesn’t hang every time a method is called.
I would urge developers to avoid writing multithreaded code (using System.Threading) wherever possible. It’s a pain in the backside to debug and is the modern day GOTO – put simply it makes code less maintainable. Consider whether there is a better architecture that can be used – for example: WCF is inherently multithreaded and SvcUtil will automatically generate asynchronous versions of methods in the proxy, so breaking an application into services allows the context (i.e. the WCF host) to manage the nuts and bolts of concurrency. The Workflow Foundation is another useful tool in the multithreaded arsenal as it enables developers to define component interaction in terms of business logic, once again letting the context manage threading (David Chappell has a first-rate guide here). Then there’s the Parallel extensions in .NET 4 which simplify taking advantage of multiple threads – physical or logical.
I’m still curious as to how many branches of development are left that require low-level poking around. All war stories gratefully received.