I have a method in C# that I want to run from multiple threads for lets say 20 times in a console app, on a 4 core machine. The problem I am facing is that the results are not what I expect them to be. When I run the method 25 times sequentially, the time taken is X and I can see in perfmon that max CPU is 100% (it tells me that it is using 1 core). Running the same method using multiple threads, I expect the execution time to be X/4 and also I expect the max CPU usage in perfmon to be 400% (since it is a 4 core machine). However, I can only see that the execution time is X/2 and the max CPU usage has never been more than 275%. I have tried various things such as creating my own threads, using threasdpool etc. and nothing seems to work. Can somebody please explain/help me understand it better?
Other interesting thing is that if I replace my method with a dummy task using Thread.SpinWait(x)
the execution time is X/4 and I can see max CPU going to 400%. This tells me that something is wrong in my method and I don't understand what it is. I have no locks/sleep anywhere in my method. Following is the code I use to execute:
public static void DoWorkParallel()
{
var s = new List<string> { "a", "b", "c", "d", "e", etc. };
s.ParallelForEach2(x =>
{
MyTask(x);
});
}
public static void DoWorkSequential()
{
var s = new List<string> { "a", "b", "c", "d", "e", etc. };
foreach (var ss in s)
{
MyTask(x);
}
}
public static void ParallelForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
var results = collection.Skip(1).Select(item => new
{
action,
res = action.BeginInvoke(item, null, null)
}).ToArray();
action(collection.First()); /* let the mainthread do a job too*/
foreach (var r in results)
{
r.action.EndInvoke(r.res); /*then wait the rest of time */
}
}
Although you can take advantage of multithreading to perform several tasks simultaneously and increase the application's throughput, it should be used judiciously. Incorrect usage of multithreading may result in high CPU usages or increased CPU cycles and can drastically reduce your application's performance.
The ultimate goal of multithreading is to increase the computing speed of a computer and thus also its performance. To this end, we try to optimize CPU usage. Rather than sticking with a process for a long time, even when it's waiting on data for example, the system quickly changes to the next task.
Core Settings In Windows 10Type 'msconfig' into the Windows Search Box and hit Enter. Select the Boot tab and then Advanced options. Check the box next to Number of processors and select the number of cores you want to use (probably 1, if you are having compatibility issues) from the menu. Select OK and then Apply.
Each core contains a complete CPU capable of executing a thread. Many modern processors support hyperthreading: each physical core behaves as if it is actually two cores, so it can run two threads simultaneously (e.g. execute one thread while the other is waiting on a cache miss).
Thread.SpinWait
is running in a tight loop, performing no I/O and accessing no memory -- it's doing no useful work, so comparing its CPU usage to that of your task is a fallacy.
Without details of what your task is doing (whether it accesses files, waits on mutexes, etc.), it's difficult to determine what's going on.
One thing you can do is to add a Stopwatch
instance to your task, and use it to print the time elapsed for each invocation. Compare the results of running tasks with DoWorkSequential
and ParallelForEach
-- each invocation should take the same amount of time regardless of the method. If the tasks run by ParallelForEach
are taking longer, it could indicate you have, say, a mutex that is in contention and needs to be replaced with another locking method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With