As custom software applications become more complex and offer larger and more expansive feature sets, the corresponding need for greater application responsiveness and more powerful processing to accomplish that has grown exponentially. Multicore computer systems deliver the platform with which software developers, especially .net software developers can develop applications that leverage multiple threads, thus providing the speed and performance that users expect from an application. Multithreading (or parallelism, if you’ve been in this business for too long, as some of us have) is the single most important speed and efficiency feature available to developers in the .NET Framework. Although some developers might argue that LINQ, Garbage Collection and a host of other features native to the .NET Framework are more innovative, unique and relevant, none of those features gives the developer the power that .NET’s simple, powerful and extensible multithreading capabilities can. Great as those other features are, without multithreading, we’re stuck in a world of processing One. Thing. At. A. Time.
But what’s so important about multithreading that makes it the greatest feature of the .NET Framework? Certainly, most, if not all other development platforms provide a method for handling multiple tasks across various threads. None, however, do it with the grace, simplicity, and power of the .NET Framework and C#. Parenthetically, I have nothing against VB.NET, C++, F# and the host of other .NET programming languages. Although I prefer C# and feel it’s superior to the others in its economy of syntax, each of the .NET languages can leverage the Framework’s multithreading tools and libraries as efficiently as the next.
To illustrate how important multithreading is in the modern world of .net and C# custom software application development, imagine a world full of computers that have a single CPU with a single core, capable of executing just one operation at a time. While this operation runs, all other operations would need to be paused – causing the computer-wide appearance of unresponsiveness or freezing to the end-user. Further, imagine there’s a bug in this operation, which once encountered ties up this single core running that single operation, not moving on until it finishes the operation, which is now stuck on the bug. The only way out might be a quick index finger to the machine’s power button. Stephen King could not pen a more terrifying nightmare…Threads to the rescue! Luckily, we live in a world of hardware and operating systems designed to run each individual application within its own dedicated process. Each application is allocated its very own dedicated virtual memory, each process running in its own thread – very much like a virtual CPU.
The .NET Framework presents the Thread class for developers to specify distinct threads for any process within their application. As part of the System.Threading namespace, the Thread class is not commonly leveraged directly within an application, but when it is it’s incredibly powerful in that it provides the developer with control over ALL the configuration options available for threads within a .NET app. Since creating and disposing of threads comes at a cost to performance, especially when many threads are being used. A Thread Pool provides a method to store threads instead of killing them when they finish, such that when your app is done with a thread you can send it to the pool and reuse it whenever a request for a thread comes in. This way, a developer can queue a work item to be picked up by an available thread, just “wading in the thread pool”. Simple, fast, efficient. Again, other languages provide similar threading capabilities, none with the grace and elegance of C# and .NET. For when there’s a LOT of work to be done in parallel, using the Parallel class from the System.Threading.Tasks namespace provides further capabilities along with the ability to take a larger task and split in into a number of related smaller tasks, all executed concurrently. This works quite well when the code in your app does not need to be executed in sequence.
Perhaps the most relevant and powerful feature of the .NET Framework’s Threading world are Tasks and the async and await keywords. Threads are not without their challenges; should you want to return a value from a thread or even be notified when an operation has finished, for example. Tasks make that possible. Even more interesting are the async and await keywords, which provide special features for handling I/O operations in an Asynchronous manner, freeing threads up to continue other operations without having to wait for input/output tasks to complete. Tasks and async/await are deep enough subjects that they warrant their very own blog posts (which I will include in my very next post!).
Without the .NET’s powerful Multithreading capabilities, we’d live in a world of turtle-slow applications and frustrated end users. While many other programming platforms implement multithreading on their own level, none of them doe sit with the power and flexibility of the .NET Framework. Stay tuned for an upcoming post when I’ll take a deeper dive into Tasks, async and await.
For more information on multithreading and the .NET Framework, visit https://docs.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading
Exigent Technologies provides custom software development services in NJ and NY. Contact then at (877) EXIGENT.