Faster .Net With Concurrency

Selcuk Köse
hepsiburadatech
Published in
6 min readApr 13, 2024

Have you ever struggle with your app’s performance? You tried to optimize your Database queries etc. but still the same problem? Maybe you are not using the full power your resources on your machine.

There is a full of resources on your machine like a treasury that is waiting to be fund somewhere. The key to unleash that power is “Concurrency and Asynchronous Programming”. My purpose by this article is showing you how you can boost your .Net apps by applying them.

.Net provide rich set of functions under System.Threading and System.Threading.Tasks namespaces, these namespace gives you ability to apply concurrency in your application.

For this article I have prepared a sample project and you can inspect that project for concrete examples:

https://github.com/selcukkose/multithreading

Different Paths To Create Threads

The simplest way of creating a thread is creating an instance of Thread class like the following code:

var t = new Thread(() =>
{
for (var i = 0; i < 1000; i++)
{
Console.Write("x");
}
});
t.Start();

By creating an instance of Thread class we make sure a thread is created on the operating system and the given method is ran.

Creating a thread is a good way to make sure the program is not blocked until the operation is completed, but do you think it is the best way for this?Can we do it in a better way?

The problem with creating thread is the thread creation operation itself is a time consuming event and for the operation that is not complex enough it is even slower than synchronous version. If you don’t want to waste time by creating a new thread for your computation .Net has ThreadPool structure. ThreadPool has pre-created threads in it and when a new thread creation request received it uses one of the idle threads instead of creating a new one. By this way the program doesn’t spend time for creating a thread in the system.

A ThreadPool thread can be used in the following way:

Task.Factory.StartNew(() =>
{
for (var i = 0; i < 1000; i++)
{
Console.Write("x");
}
});

This way it is much more better but if the thread operation takes too much time then you would block one of the ThreadPool thread for a long time which is not good. At this case specifying TaskCreationOptions.LongRunning option as parameter in Task.Factory.Startnew method or using a new Thread would be better.

Synchronization Between Threads

When our code run on multiple threads and those threads try to update a value it might end up with wrong calculation result because the threads are not applying changes in order. To make all the running threads sync we need to use one of the Synchronization structure in .Net. We will inspect them one by one.

The first and the most known option is lock. The lock mechanism is good enough for short locking operations but it needs to be used carefully with long operations because it uses loop to make other threads wait until the lock is released. You might also consider using SpinLock too if you have a few instructions to block.

Another option is using Mutex for synchronization, the best property of Mutex it works in Operating System level and it also works even between processes. If more than one process use the same resource concurrently you have to use Mutex but problem with the Mutex is it is much more slower than other options. Because it is working in OS level and acquiring it requires more time.

I also want to mention Interlocked class here, it can be thought as syntactic sugar but it is more than that, because it handles variable volatility and locking mechanism for you and do what you ever want to do easily. It doesn’t provide interprocess locking so it’s not powerful as Mutex and you can think Interlocked class like lock.

More Advanced Synchronization Options

More than basic synchronization options .Net offers some more advanced structures to make complex synchronization operations easier and even possible. These options are working by signaling each other in various ways.

The first option is EventWaitHandle, this class provide signaling mechanism between threads to wait each other on certain point.

The WaitOne method of the EventWaitHandle class makes sure the current thread wait on the line until another thread realases the lock by calling Set method.

EventWaitHandle can be used in two different modes: ManualReset and AutoReset, the difference between those modes is AutoReset mode sets the value to the default when WaitOne method exectuted which is ManualReset doesn’t. For each modes seperate classes named AutoResetEvent and ManualResetEvent are available and they can be usable instead of providing modes as parameter.

EventWaitHandle is a good to make threads synchronized one by one, it is like making threads play ping pong together, do some job wait until another one do something and then continue etc. But you may also want them all do the work together and wait each other to make it done. To achieve this behaivour you can Barrier.

Similar behaviour can be done by using CountDownEvent but it gives more controls than Barrier. You can specify where to make the thread wait by using Wait method in CountDownEvent class when Barrier’s SignalAndWait method only signals and waits at the same line.

Asynchronous Programming

So far we have used creating new threads to make computing faster, do we always have to create a new thread or use another thread from thread pool divide our calculation and make it faster? Can we do something in the thread that we are already running on? Yes, we can, almost every program has some I/O bound calculations in it and we have to wait until the I/O operations are done in synchronous way.

To solve this problem Asynchronous Programming can be used, by this way when the .Net compiler see an operation that might take long time it doesn’t wait for it to be completed. It just starts it and continues to other operation that can be done without waiting.

To understand how async programming works exatcly let’s imagine you are preparing a table for dinner and you order a pizza, would you just sit and wait until the pizza comes? No, you can do other things like go to shop and by a coke and maybe prepare a salad etc. You would do other things instead of just waiting but be careful you are still one person there is no other person to help you with your job.

.Net handles this ability by using state machine, it doesn’t create any thread for it.

Task Parallel Library (TPL)

Task Parallel Library (TPL) makes our life easier while working with multithreading in .Net. It provides 3 methods for that purpose:

Parallel.Invoke();

Runs given actions in parallel.

Parallel.ForEach(); and Parallel.For();

Runs actions given for the loop in parallel. We can easily think those loop work always faster than for and foreach loops but unfortunately it doesn’t work that way. If the operations in loop is not complex enough to use TPL it will be faster to use normal for and foreach loop otherwise using TPL methods would be even slower.

I’ve tried to make a overlook about .Net concurrency abilities and I hope it will be helpful to you, thanks for reading it :).

--

--