Only a Curious Mind
Only a Curious Mind

Reputation: 2857

What is the better number of threads running simultaneous for specific processor?

I have a computer with an 8-core processor, and I have a doubt about what's the max number of threads (software, don't thread of processor.) that my computer needs to use the max potencial of your 8-core.

I'm creating 160 threads simultaneous, so each core of my processor will process about ~20 threads, is it correct?

My questions are:

Upvotes: 2

Views: 2488

Answers (2)

Luaan
Luaan

Reputation: 63722

I'm creating 160 threads simultaneous, so each core of my processor will process about ~20 threads, is it correct?

Not quite. Each core can only process a single thread at a time. When the OS decides the thread had enough of the spotlight, it will switch it out for another thread. If you can do the same work in 8 threads, you're going to have the same throughput plus the savings you get from avoiding unnecessary context switching.

20 threads by core of processor is a good number?

No. One thread per core is the spot. Hyperthreaded cores count for two, approximately - how well that works varies.

Independent the number of threads running, its will be divided equality by the number of cores?

No. This is decided by the operating system, which will tend to take many different things in its decision-making. Also, threads which are blocking will not execute anywhere. It's actually quite possible for a few of those threads to hog much more CPU time than others.

How to know whats the better number of threads according with my processor?

Use higher level constructs than threads. That means using the thread pool for simple work items, Parallel.For and family for "synchronous" paralellism, and asynchronous Tasks for complex asynchronous work tasks (including thread pool fragments). There really aren't many good reasons to manually create threads anymore - unless you really know what you're doing, and why it matters to have it on a dedicated thread.

The critical point is this only applies to CPU work. You can easily have a single thread handling a hundred separate asynchronous tasks at the same time. This is especially easy to work with when using await against asynchronous APIs. Single thread per CPU can easily get you 100% utilization as long as it actually does CPU work. If it doesn't, you want to use asynchronous I/O anyway - there's no point in wasting threads (accompanied with their cost in memory, switching overhead, overtasking the scheduler, garbage collection...) while waiting.

The typical example would be an asynchronous web service dealing with some database work:

string GetUserName(Guid userId)
{
  return Db.GetUser(userId).Name;
}

This synchronous method will take up the request thread while processing the DB request. If your DB requests takes a second, and you have 2000 requests at the same time, you'll need 2000 threads handling the requests. However, DB requests are just asynchronous I/O - the thread is basically waiting for the response from the DB to come back. The thread is wasted waiting.

Instead, you could use an asynchronous API:

async Task<string> GetUserName(Guid userId)
{
  var user = await Db.GetUserAsync(userId);

  return user.Name;
}

The code is almost identical, but the await construct doesn't actually block the request thread - it basically says "Okay, I'm done, you can use this thread for something else. I'll ping you back when I'm ready to continue.". This patterns means that you never need more threads than CPU cores - if the CPU is at 100%, there's no point in adding more threads to handle the load. If it's not, it means some thread isn't doing any CPU work - which is fine, it will be used when another piece of work comes around. And now, instead of having 2000 threads handling 2000 requests, you have 8 threads handling the same 2000 requests.

Upvotes: 8

Peter
Peter

Reputation: 38455

The best count would be one per virtual core (a core with HT counts as 2 virtual cores).

But you should not implement this logic by your self use Parallel.ForEach example taken from msdn, also there are other options look here also if there is alot of delays involved like reading a file or waiting for network traffic i would recommend using async functions (see example 2, also from msdn):

using System;
using System.Drawing; // requires system.Drawing.dll 
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class SimpleForEach
{
    static void Main()
    {
        // A simple source for demonstration purposes. Modify this path as necessary. 
        string[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg");
        string newDir = @"C:\Users\Public\Pictures\Sample Pictures\Modified";
        System.IO.Directory.CreateDirectory(newDir);

        //  Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
        Parallel.ForEach(files, currentFile =>
        {
            // The more computational work you do here, the greater  
            // the speedup compared to a sequential foreach loop. 
            string filename = System.IO.Path.GetFileName(currentFile);
            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(currentFile);

            bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
            bitmap.Save(System.IO.Path.Combine(newDir, filename));

            // Peek behind the scenes to see how work is parallelized. 
            // But be aware: Thread contention for the Console slows down parallel loops!!!
            Console.WriteLine("Processing {0} on thread {1}", filename,
                                Thread.CurrentThread.ManagedThreadId);

        } //close lambda expression
             ); //close method invocation 

        // Keep the console window open in debug mode.
        Console.WriteLine("Processing complete. Press any key to exit.");
        Console.ReadKey();
    }
}

Example 2:

// Add a using directive and a reference for System.Net.Http. 
using System.Net.Http;

// Add the following using directive. 
using System.Threading;


namespace ProcessTasksAsTheyFinish
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();

            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

            try
            {
                await AccessTheWebAsync(cts.Token);
                resultsTextBox.Text += "\r\nDownloads complete.";
            }
            catch (OperationCanceledException)
            {
                resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
            }
            catch (Exception)
            {
                resultsTextBox.Text += "\r\nDownloads failed.\r\n";
            }

            cts = null;
        }


        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            // ***Create a query that, when executed, returns a collection of tasks.
            IEnumerable<Task<int>> downloadTasksQuery =
                from url in urlList select ProcessURL(url, client, ct);

            // ***Use ToList to execute the query and start the tasks. 
            List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

            // ***Add a loop to process the tasks one at a time until none remain. 
            while (downloadTasks.Count > 0)
            {
                    // Identify the first task that completes.
                    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

                    // ***Remove the selected task from the list so that you don't 
                    // process it more than once.
                    downloadTasks.Remove(firstFinishedTask);

                    // Await the completed task. 
                    int length = await firstFinishedTask;
                    resultsTextBox.Text += String.Format("\r\nLength of the download:  {0}", length);
            }
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "http://msdn.microsoft.com",
                "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "http://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "http://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "http://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
        {
            // GetAsync returns a Task<HttpResponseMessage>. 
            HttpResponseMessage response = await client.GetAsync(url, ct);

            // Retrieve the website contents from the HttpResponseMessage. 
            byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

            return urlContents.Length;
        }
    }
}

Upvotes: 1

Related Questions