Does a multithreaded task not use a processor?

I have a C # method that I want to run from multiple threads, so let's say 20 times in a console application on a 4-core computer. The problem I am facing is that the results are not what I expect from them. When I run the method 25 times in a row, it takes X, and I can see in perfmon that the maximum processor is 100% (it tells me that it uses 1 core). By running the same method using multiple threads, I expect the runtime to be X / 4, and I also expect the maximum CPU utilization in perfmon to be 400% (since this is a 4-core machine). However, I can only see that the runtime is X / 2, and the maximum CPU usage never exceeded 275%. I tried various things such as creating my own threads, using threasdpool, etc., and nothing works. Can someone explain / help me understand this better?

Another interesting one is that if I replaced my method with a dummy task using Thread.SpinWait(x) , the runtime is X / 4 and I can see that the maximum CPU is 400%. This tells me that something is wrong with my method, and I don’t understand what it is. I have no locks / sleep in my method. Below is the code that 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 */ } } 
+6
source share
2 answers

Thread.SpinWait runs in a narrow cycle, does not perform I / O and does not receive any memory - this does not do any useful work, so comparing its CPU usage with the needs of your task is a mistake.

Without the details of what your task is doing (regardless of whether it accesses files, waits on mutexes, etc.), it is difficult to determine what is happening.

One thing you can do is add a Stopwatch instance to your task and use it to print the elapsed time for each call. Compare the results of the tasks with DoWorkSequential and ParallelForEach - each call should take the same amount of time regardless of the method. If the tasks performed by ParallelForEach take more time, this may mean that you have, say, a mutex that is in conflict and needs to be replaced with another locking method.

+1
source

You might want to set MaxDegreeOfParallelism to 4 in the ParallelOptions parameter to call Parallel.Foreach. If you do not, dotnet4 uses a lot of worker threads; their management and synchronization overhead can be a bit wasteful. I had a similar problem and it worked for me.

http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.aspx

In addition, everything is simplified here. Remember that when you use tight-wrought parallelism, you trade records per second (processor core performance) versus quarterly records (programmer performance).

0
source

Source: https://habr.com/ru/post/891950/


All Articles