Last active
April 3, 2024 14:27
-
-
Save heiswayi/296c4de4db6e34798be28f90aa47cf47 to your computer and use it in GitHub Desktop.
C# Multithreadings (Thread, Threadpool, Task & BackgroundWorker) vs single threading experiment. https://nrird.com/blog/multithreading-programming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Diagnostics; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace MultithreadingVsSingleThreading | |
{ | |
internal class Program | |
{ | |
#region Fields | |
private static int selectedMode; | |
// The number of threads to be spawned. | |
private const int threadCount = 1000; | |
// The total number of spins the actual work is carried out repeatedly. | |
private const int totalCount = 100000; | |
#endregion Fields | |
#region Methods | |
private static void Main(string[] args) | |
{ | |
Console.Title = "Multithreading vs Single Threading Example"; | |
start: | |
Console.WriteLine("Select which mode to run:-"); | |
Console.WriteLine(" (1) Multithreading"); | |
Console.WriteLine(" (2) Single Threading"); | |
Console.WriteLine(" (3) Threadpool"); | |
Console.WriteLine(" (4) Task"); | |
Console.WriteLine(" (5) BackgroundWorker"); | |
var input = Console.ReadLine(); | |
if (input.Length == 0) | |
{ | |
Console.Clear(); | |
goto start; | |
} | |
else if (Convert.ToInt32(input) == 0 || Convert.ToInt32(input) >= 6) | |
{ | |
Console.Clear(); | |
goto start; | |
} | |
else | |
{ | |
selectedMode = Convert.ToInt32(input); | |
} | |
Thread.CurrentThread.Priority = ThreadPriority.Highest; | |
Stopwatch watch = new Stopwatch(); | |
Console.Clear(); | |
watch.Start(); | |
try | |
{ | |
HandleMode(selectedMode); | |
watch.Stop(); | |
Console.WriteLine("Work complete!"); | |
Console.WriteLine("Time elapsed: {0}", watch.Elapsed); | |
Console.WriteLine(Environment.NewLine); | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine("Press Enter key to test again or Esc to quit"); | |
Console.ResetColor(); | |
var key = Console.ReadKey(); | |
if (key.Key == ConsoleKey.Enter) | |
{ | |
Console.Clear(); | |
goto start; | |
} | |
if (key.Key == ConsoleKey.Escape) Environment.Exit(0); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e.Message); | |
} | |
Console.ReadLine(); | |
} | |
/// <summary> | |
/// Performs the task based on user defined option. | |
/// </summary> | |
/// <param name="mode"></param> | |
private static void HandleMode(int mode) | |
{ | |
switch (mode) | |
{ | |
case 1: | |
Console.WriteLine("Using Thread() | No. of threads = {0}", threadCount); | |
Console.WriteLine("Initialize work..."); | |
RunThreadMode(); | |
break; | |
case 2: | |
Console.WriteLine("Using this Main() thread, directly call ComplexWork({0})", totalCount); | |
Console.WriteLine("Initialize work..."); | |
ComplexWork(totalCount); | |
break; | |
case 3: | |
Console.WriteLine("Using ThreadPool.QueueUserWorkItem() | No. of threads = {0}", threadCount); | |
Console.WriteLine("Initialize work..."); | |
RunInThreadPool(); | |
break; | |
case 4: | |
Console.WriteLine("Using Task() | No. of threads = {0}", threadCount); | |
Console.WriteLine("Initialize work..."); | |
RunTaskMode(); | |
break; | |
case 5: | |
Console.WriteLine("Using BackgroundWorker() | No. of threads = {0}", threadCount); | |
Console.WriteLine("Initialize work..."); | |
RunInBackgroundWorker(); | |
break; | |
default: | |
break; | |
} | |
} | |
#region Work Task | |
/// <summary> | |
/// Performs CPU intensive task. | |
/// </summary> | |
/// <param name="n"></param> | |
private static void ComplexWork(int n) | |
{ | |
for (int j = 0; j < n; j++) | |
{ | |
for (int i = 1; i < 100; i++) | |
{ | |
Fac(i); | |
} | |
} | |
} | |
/// <summary> | |
/// Calculates the factorial of a number. | |
/// </summary> | |
/// <param name="n"></param> | |
/// <returns></returns> | |
private static double Fac(double n) | |
{ | |
if (n > 1) | |
{ | |
return n * Fac(n - 1); | |
} | |
else | |
{ | |
return 1; | |
} | |
} | |
#endregion Work Task | |
/// <summary> | |
/// Spawns new threads based on the thread count and starts the activity. | |
/// </summary> | |
private static void RunThreadMode() | |
{ | |
Thread[] t = new Thread[threadCount]; | |
for (int i = 0; i < threadCount; i++) | |
{ | |
t[i] = new Thread(() => | |
{ | |
ComplexWork(totalCount / threadCount); | |
}); | |
t[i].Priority = ThreadPriority.Highest; | |
t[i].Start(); | |
} | |
// Waits for all the threads to finish. | |
foreach (var ct in t) | |
{ | |
ct.Join(); | |
} | |
} | |
/// <summary> | |
/// Executes the task in a thread pooling context. | |
/// </summary> | |
private static void RunInThreadPool() | |
{ | |
using (CountdownEvent signaler = new CountdownEvent(threadCount)) | |
{ | |
for (int i = 0; i < threadCount; i++) | |
{ | |
ThreadPool.QueueUserWorkItem((x) => | |
{ | |
ComplexWork(totalCount / threadCount); | |
signaler.Signal(); | |
}); | |
} | |
signaler.Wait(); | |
} | |
} | |
/// <summary> | |
/// Creates a new task based on the TPL library. | |
/// </summary> | |
private static void RunTaskMode() | |
{ | |
Task[] taskList = new Task[threadCount]; | |
for (int i = 0; i < threadCount; i++) | |
{ | |
taskList[i] = new Task(new Action(() => | |
{ | |
ComplexWork(totalCount / threadCount); | |
})); | |
taskList[i].Start(); | |
} | |
Task.WaitAll(taskList); | |
} | |
/// <summary> | |
/// Starts BackgroundWorker to perform the same action. | |
/// </summary> | |
private static void RunInBackgroundWorker() | |
{ | |
BackgroundWorker[] backgroundWorkerList = new BackgroundWorker[threadCount]; | |
using (CountdownEvent signaler = new CountdownEvent(threadCount)) | |
{ | |
for (int i = 0; i < threadCount; i++) | |
{ | |
backgroundWorkerList[i] = new BackgroundWorker(); | |
backgroundWorkerList[i].DoWork += delegate (object sender, DoWorkEventArgs e) | |
{ | |
ComplexWork(totalCount / threadCount); | |
signaler.Signal(); | |
}; | |
backgroundWorkerList[i].RunWorkerAsync(); | |
} | |
signaler.Wait(); | |
} | |
} | |
#endregion Methods | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment