none
How to use Multi-Core CPU to increase performance RRS feed

  • Question

  • Hello:

    I have the following C# (.NET Core Version 2.2) project built by Visual Studio 2019 (Version 16.1.5) on Windows 10 (Version 1903)

    using System;
    using System.Threading.Tasks;
    
    namespace MultiCorePerformance1
    {
        class Program
        {
            static async Task DoProdJob(int prod_item1)
            {
                if (prod_item1 >= 1)
                    Console.WriteLine("Save prod_item1 into [PROD_TABLE], Done @{0}", DateTime.Now.ToLocalTime());
                await Task.Delay(0);   
            }
    
            static async Task DoTotalJob(int total_item1)
            {
                if (total_item1 >= 2)
                    Console.WriteLine("Save total_item1 into [TOTAL_TABLE], Done @{0}", DateTime.Now.ToLocalTime());
                await Task.Delay(0);
            }
    
            static async Task DoDifferJob(int diff_item1)
            {
                if (Math.Abs(diff_item1) >= 1)
                    Console.WriteLine("Save diff_item1 into [DIFF_TABLE], Done @{0}", DateTime.Now.ToLocalTime());
                await Task.Delay(0);
            }
    
            static async void Main()
            {
                int item1 = 1, item2 = 2;
                int prod_items = item1 * item2;
                int total_items = item1 + item2;
                int differ_items = item1 - item2;
                await DoProdJob(prod_items);
                await DoTotalJob(total_items);
                await DoDifferJob(differ_items);
            }
        }
    }
    

    The code works OK, but the performance is not good. As this is the example code, the real code, each DoXXXJob contains using Puppeteer-Sharp to grab web page information and upload HTTP post data by HttpClient.

    For each of the operation, the speed seems to be OK. For example, Puppeteer-Sharp grabbing web page information takes less than 10 milliseconds; HTTP post by HttpClient takes 300ms to 500ms.

    I have total 8 of such DoXXXJob, each one will take place with different conditions, depend on the production, total and difference of 2 items: item1 and item2.

    The biggest issue now is the performance is not good.

    For example, the average time I see the output from Done @{0}", DateTime.Now.ToLocalTime());

    Is about 1 minute, 2 minutes or even much longer after I got the both items.

    As my PC comes with ADM CPU with 16 core.

    I would like to know if I can use C# to fully utilize my multi-core CPU to boost the performance. I think if the output from Done @{0}", DateTime.Now.ToLocalTime()) is mostly from 10 to 15 seconds after I get the both items value, then the performance is good enough.

    Please advice, which direction I should go. Better to provide either document link or some sample codes.

    Thanks,

    Monday, July 8, 2019 3:13 PM

Answers

  • Have you tried this?

       await DoProdJob(prod_items).ConfigureAwait( false );

       await DoTotalJob(total_items).ConfigureAwait( false );

       await DoDifferJob(differ_items).ConfigureAwait( false );

    • Marked as answer by zydjohn Wednesday, July 10, 2019 2:17 PM
    Tuesday, July 9, 2019 6:16 AM

All replies

  • C# (and Windows) will properly run across any # of CPUs if you're doing enough work to warrant it. Specifically to max out 16 CPUs you'd have to be running at least 16 threads or tasks at the same time. This is pretty unrealistic for most apps.

    Your code as written is sequential so you'll never be taking advantage of the CPUs beyond the 1 or 2 it takes to run your code. Calling `await` blocks the calling thread so there is no real parallelism going on here. To run work in parallel you'll need to start the tasks you want to run at the same time and capture the Task that comes back. Don't use await as it blocks. Once all the work is running you can await on all the tasks to block until they complete.

    class Program
    {
        static async Task DoProdJob ( int prod_item1, int delay )
        {
            Console.WriteLine("Saving prod_item1 into [PROD_TABLE]");
    
            //Let's make this interesting
            await Task.Delay(delay);
    
            Console.WriteLine("Saved prod_item1 into [PROD_TABLE]");
        }
    
        static async Task DoTotalJob ( int total_item1, int delay )
        {
            Console.WriteLine("Saving total_item1 into [TOTAL_TABLE]");
    
            //Let's make this interesting
            await Task.Delay(delay);
    
            Console.WriteLine("Saved total_item1 into [TOTAL_TABLE]");
        }
    
        static async Task DoDifferJob ( int diff_item1, int delay )
        {
            Console.WriteLine("Saving diff_item1 into [DIFF_TABLE]");
    
            //Let's make this interesting
            await Task.Delay(delay);
    
            Console.WriteLine("Saved diff_item1 into [DIFF_TABLE]");
        }
    
        static void Main ()
        {
            int item1 = 1, item2 = 2;
            int prod_items = item1 * item2;
            int total_items = item1 + item2;
            int differ_items = item1 - item2;
    
            var rnd = new Random();
    
            //Start all the tasks
            var tasks = new[]
            {
                DoProdJob(prod_items, rnd.Next(10000)),
                DoTotalJob(total_items, rnd.Next(10000)),
                DoDifferJob(differ_items, rnd.Next(10000))
            };
    
            //Wait for them to finish
            Console.WriteLine("Waiting");
            Task.WaitAll(tasks);
    
            Console.WriteLine("Done");
        }
    }

    Of course there are other approaches as well but since you're using Task here I've stuck with this. Also note that there is a limit on how many calls you can make to the same endpoint from the same client at any one time. This is for security reasons and can be changed but in general you're only going to get about 2 connections to the same client at the same time. Hence if you're starting up 10 tasks to all talk to the same server endpoint then you're likely going to see only 2 actually doing any work at any one time while the rest are blocked waiting. This is by design.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, July 8, 2019 6:21 PM
    Moderator
  • Have you tried this?

       await DoProdJob(prod_items).ConfigureAwait( false );

       await DoTotalJob(total_items).ConfigureAwait( false );

       await DoDifferJob(differ_items).ConfigureAwait( false );

    • Marked as answer by zydjohn Wednesday, July 10, 2019 2:17 PM
    Tuesday, July 9, 2019 6:16 AM
  • Hi zydjohn Fortis, 

    Thank you for posting here.

    I have found a reference about Parallel Processing:

    How to Get Started with Multi-Core: Parallel Processing You Can Use

    Hope it can help you.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, July 9, 2019 7:36 AM
    Moderator