Подтвердить что ты не робот

Как я создаю потоки на разных ядрах процессора?

Скажем, у меня была программа на С#, которая делала что-то дорогостоящее вычислительное, например, кодирование списка WAV файлов в MP3. Обычно я кодировал файлы по одному, но, допустим, я хотел, чтобы программа выяснила, сколько ядер ядра у меня было, и закручиваем поток кодирования на каждом ядре. Итак, когда я запускаю программу на четырехъядерном процессоре, программа вычисляет ее четырехъядерный процессор, и есть четыре ядра для работы, а затем порождает четыре потока для кодирования, каждый из которых запускается самостоятельно ЦПУ. Как мне это сделать?

И будет ли это иначе, если бы ядра были распределены по нескольким физическим процессорам? Как и в случае, если у меня была машина с двумя четырёхъядерными процессорами на ней, есть ли какие-либо особые соображения или восемь ядер на двух матрицах считаются равными в Windows?

4b9b3361

Ответ 1

Не беспокойтесь об этом.

Вместо этого используйте Пул потоков. Пул потоков - это механизм (фактически класс) структуры, который вы можете запросить для нового потока.

Когда вы запрашиваете новый поток, он либо даст вам новый, либо закроет работу, пока поток не будет освобожден. Таким образом, структура отвечает за принятие решения о том, что она должна создавать больше потоков или не зависит от количества существующих процессоров.

Изменить: Кроме того, как уже упоминалось, ОС отвечает за распределение потоков между различными ЦП.

Ответ 2

Это не обязательно так просто, как использование пула потоков.

По умолчанию пул потоков выделяет несколько потоков для каждого ЦП. Поскольку каждый поток, участвующий в работе, которую вы выполняете, имеет затраты (накладные расходы на задачи, использование очень ограниченного ЦП L1, L2 и, возможно, кеша L3 и т.д.), Оптимальное количество используемых потоков - = количество доступных CPU - если только каждый поток не запрашивает службы у других машин - например, высоко масштабируемый веб-сервис. В некоторых случаях, особенно в тех случаях, когда речь идет о чтении и записи жесткого диска, чем о работе процессора, вы можете быть лучше с 1 потоком, чем с несколькими потоками.

Для большинства приложений и, конечно же, для кодирования WAV и MP3 вы должны ограничить количество рабочих потоков количеством доступных CPU. Вот код С#, чтобы найти количество процессоров:

int processors = 1;
string processorsStr = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");
if (processorsStr != null)
    processors = int.Parse(processorsStr);

К сожалению, это не так просто, как ограничение количества процессоров. Вы также должны учитывать производительность контроллера (ов) жесткого диска и дисков (дисков).

Единственный способ найти оптимальное количество потоков - пробная ошибка. Это особенно актуально, если вы используете жесткие диски, веб-службы и т.д. С жесткими дисками вам может быть лучше не использовать все четыре процессора на вашем четырехъядерном процессоре. С другой стороны, с некоторыми веб-службами вам может быть лучше сделать 10 или даже 100 запросов на процессор.

Ответ 3

В случае с управляемыми потоками сложность выполнения этого процесса выше, чем у собственных потоков. Это связано с тем, что потоки CLR напрямую не привязаны к потоку собственной ОС. Другими словами, CLR может переключать управляемый поток из собственного потока в собственный поток, как он считает нужным. Функция Thread.BeginThreadAffinity предоставляется для размещения управляемого потока в режиме блокировки с потоком собственной ОС. В этот момент вы можете поэкспериментировать с использованием встроенного API, чтобы дать возможность связать родной поток с потоком. Как все говорят здесь, это не очень хорошая идея. Фактически существует документация, предполагающая, что потоки могут получать меньше времени обработки, если они ограничены одним процессором или ядром.

Вы также можете изучить класс System.Diagnostics.Process. Там вы можете найти функцию для перечисления потоков процессов в виде коллекции объектов ProcessThread. Этот класс имеет методы установки ProcessorAffinity или даже установки предпочтительного процессора - не уверен, что это такое.

Отказ от ответственности: у меня возникла аналогичная проблема, когда я думал, что CPU были использованы и исследовали много всего этого; однако, основываясь на всем, что я читал, оказалось, что это была не очень хорошая идея, о чем свидетельствуют комментарии, размещенные здесь. Тем не менее, это все еще интересно и опыт для экспериментов.

Ответ 4

Вам не придется беспокоиться о том, чтобы сделать это самостоятельно. У меня многопоточные .NET-приложения, работающие на двухъядерных машинах, и независимо от того, как запускаются потоки, будь то через ThreadPool или вручную, я вижу приятное равномерное распределение работы по всем ядрам.

Ответ 5

Вы можете это сделать, написав программу внутри вашей программы.

Однако вы не должны пытаться это сделать, поскольку операционная система является лучшим кандидатом для управления этими материалами. Я имею в виду, что программа пользовательского режима не должна пытаться это сделать.

Однако иногда это может быть сделано (для действительно продвинутого пользователя) для достижения балансировки нагрузки и даже для выяснения истинной многоядерной проблемы с несколькими потоками (согласование данных/кеширование кодов...), поскольку различные потоки будут действительно выполняться на разных процессорах.

Сказав это, если вы все еще хотите достичь, мы можем сделать это следующим образом. Я предоставляю вам псевдо-код для (ОС Windows), однако их можно легко сделать и в Linux.

#define MAX_CORE 256
processor_mask[MAX_CORE] = {0};
core_number = 0;

Call GetLogicalProcessorInformation();
// From Here we calculate the core_number and also we populate the process_mask[] array
// which would be used later on to set to run different threads on different CORES.


for(j = 0; j < THREAD_POOL_SIZE; j++)
Call SetThreadAffinityMask(hThread[j],processor_mask[j]);
//hThread is the array of handles of thread.
//Now if your number of threads are higher than the actual number of cores,
// you can use reset the counters(j) once you reach to the "core_number".

После вызова вышеупомянутой процедуры потоки всегда выполняются следующим образом:

Thread1-> Core1
Thread2-> Core2
Thread3-> Core3
Thread4-> Core4
Thread5-> Core5
Thread6-> Core6
Thread7-> Core7
Thread8-> Core8

Thread9-> Core1
Thread10-> Core2
...............

Для получения дополнительной информации обратитесь к руководству /MSDN, чтобы узнать больше об этих концепциях.

Ответ 6

Где каждый поток идет, как правило, обрабатывается самой ОС... так что сгенерируйте 4 потока в четырехъядерной системе, и ОС решит, какие ядра запускать каждый, что обычно будет 1 нить на каждом ядре.

Ответ 7

Задача операционной системы состоит в том, чтобы разделить потоки по разным ядрам, и она будет делать это автоматически, когда ваши потоки будут использовать много процессорного времени. Не беспокойтесь об этом. Что касается определения количества ядер вашего пользователя, попробуйте Environment.ProcessorCount в С#.

Ответ 8

Одна из причин, по которой вам не следует (как было сказано), попытаться выделить этот материал самостоятельно, заключается в том, что у вас просто недостаточно информации, чтобы делать это правильно, особенно в будущем с помощью NUMA и т.д.

Если у вас есть поток, предназначенный для чтения, и там простаивает ядро, ядро ​​запускает ваш поток, не волнуйтесь.

Ответ 9

вы не можете этого сделать, поскольку только для этой операционной системы есть привилегии. Если вы решите это..... тогда будет сложно закодировать приложения. Потому что тогда вам также нужно позаботиться о межпроцессорной связи. критические разделы. для каждого приложения вам необходимо создать собственные семафоры или мьютексы... к которым операционная система дает общее решение, делая это сама........

Ответ 10

Хотя я согласен с большинством ответов здесь, я считаю, что стоит добавить новое соображение: технология Speedstep.

При запуске интенсивного однопоточного задания на основе многоядерной системы, в моем случае Xeon E5-2430 с 6 реальными ядрами (12 с HT) под сервером Windows 2012, работа получила распространение среди всех 12 с использованием около 8,33% каждого ядра и никогда не запускает увеличение скорости. Процессор остался на частоте 1,2 ГГц.

Когда я устанавливаю привязку потока к определенному ядру, он использовал ~ 100% от этого ядра, в результате чего CPU достигает максимума на 2,5 ГГц, что более чем удваивает производительность.

Это программа, которую я использовал, которая просто зацикливает увеличение переменной. При вызове с -a он установит сродство к ядру 1. Аффинная часть была основана на этот пост.

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace Esquenta
{
    class Program
    {
        private static int numThreads = 1;
        static bool affinity = false;
        static void Main(string[] args)
        {
            if (args.Contains("-a"))
            {
                affinity = true;
            }
            if (args.Length < 1 || !int.TryParse(args[0], out numThreads))
            {
                numThreads = 1;
            }
            Console.WriteLine("numThreads:" + numThreads);
            for (int j = 0; j < numThreads; j++)
            {
                var param = new ParameterizedThreadStart(EsquentaP);
                var thread = new Thread(param);
                thread.Start(j);
            }

        }

        static void EsquentaP(object numero_obj)
        {
            int i = 0;
            DateTime ultimo = DateTime.Now;
            if(affinity)
            {
                Thread.BeginThreadAffinity();
                CurrentThread.ProcessorAffinity = new IntPtr(1);
            }
            try
            {
                while (true)
                {
                    i++;
                    if (i == int.MaxValue)
                    {
                        i = 0;
                        var lps = int.MaxValue / (DateTime.Now - ultimo).TotalSeconds / 1000000;
                        Console.WriteLine("Thread " + numero_obj + " " + lps.ToString("0.000") + " M loops/s");
                        ultimo = DateTime.Now;
                    }
                }
            }
            finally
            {
                Thread.EndThreadAffinity();
            }
        }

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentProcessorNumber();
        private static ProcessThread CurrentThread
        {
            get
            {
                int id = GetCurrentThreadId();
                return Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Single(x => x.Id == id);
            }
        }
    }
}

И результаты:

results

Скорость процессора, как показано диспетчером задач, похожа на то, что сообщает CPU-Z:

enter image description here