Многоядерный + Гиперпоточность - как потоки распределяются?

В основном, это зависит от вас, как вы хотите справиться с этим.

Я разработал некоторые API RESTful в соответствии с Руководством API REST API , в котором содержатся лучшие практики.

Согласно их рекомендациям, клиенты REST должны ожидать, что данные коллекции могут быть возвращены в размерах страниц.

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

Они используют фильтрацию в стиле «OData» , сортировку и разбиение на страницы. Я процитирую фактическую главу «фильтрация»:

Параметр $ querystring позволяет фильтровать коллекцию ресурсов, которые адресуются URL-адресом запроса. Выражение, указанное с помощью фильтра $ filter, оценивается для каждого ресурса в коллекции, и в ответ включаются только те элементы, где выражение оценивается как true. Ресурсы, для которых выражение оценивается как false или null, или какие ссылочные свойства, которые недоступны из-за разрешений, исключены из ответа (ответ на ваш вопрос: значит, вы должны вернуть пустой результат поискового вызова)

Пример: вернуть все продукты, цена которых меньше $ 10,00

GET https://api.contoso.com/v1.0/products?$filter=price lt 10.00

Значение параметра $ filter является булевым выражением.

25
задан Community 23 May 2017 в 10:29
поделиться

6 ответов

Linux имеет вполне сложный планировщик потока, который является HT знающий. Некоторые его стратегии включают:

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

Активное Выравнивание нагрузки: Если будет 3 задачи, 2 на одном физическом CPU и 1 на другом, когда второй физический процессор пойдет неактивный, то планировщик попытается переместить одну из задач к нему.

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

Так для ответа на вопрос (на Linux, по крайней мере); учитывая 2 потока на двухъядерной гиперпоточной машине, каждый поток будет работать на своем собственном физическом ядре.

8
ответ дан joshperry 28 November 2019 в 21:45
поделиться

Нормальная ОС попытается запланировать в вычислительном отношении интенсивные задачи на их собственные ядра, но проблемы возникают при запуске контекстного переключения их. Современная ОС все еще имеет тенденцию запланировать вещи на ядра, где нет никакой работы над планированием времени, но это может привести к процессам в параллельных приложениях, подкачиваемых от ядра до ядра справедливо подробно. Для параллельных приложений Вы не хотите это, потому что Вы теряете данные, которые процесс, возможно, использовал в кэшах на его ядре. Люди используют привязку процессора для управления для этого, но на Linux, семантика sched_affinity () может варьироваться много между дистрибутивами/ядрами/поставщиками, и т.д.

, Если Вы находитесь на Linux, можно портативно управлять привязкой процессора с Портативная Библиотека Привязки Процессора Linux (PLPA) . Это - то, что использование OpenMPI внутренне для проверки процессы планируются к их собственным ядрам в системах мультисокета и многоядерном; они только что отделили модуль как автономный проект. OpenMPI используется в Лос-Аламосе среди многих других мест, таким образом, это хорошо протестировано код. Я не уверен, что эквивалент находится под Windows.

5
ответ дан Todd Gamblin 28 November 2019 в 21:45
поделиться

Вероятность - по существу 0%, что ОС не использует как можно больше физических ядер. Ваша ОС не глупа. Его задание должно запланировать все, и это знает очень хорошо, какие ядра это имеет в наличии. Если это будет видеть два интенсивных ЦП потока, это удостоверится, что они работают на двух физических ядрах.

Редактирование Только для разработки немного, для высокоэффективного материала, как только Вы входите в MPI или другие серьезные платформы распараллеливания, Вы определенно хотите управлять тем, что работает на каждом ядре.

ОС предпримет своего рода попытку максимальных усилий использовать все ядра, но это не имеет долгосрочной информации, которую Вы делаете, тот "этот поток собирается работать в течение очень долгого времени", или что "мы собираемся иметь это много потоков, выполняющихся параллельно". Таким образом, это не может принять идеальные решения, что означает, что Ваш поток будет время от времени присваиваться новому ядру, что означает, что Вы столкнетесь с неудачными обращениями в кэш и подобный, который стоит небольшого количества времени. В большинстве целей это достаточно хорошо, и Вы даже не заметите различия в производительности. И это также играет по правилам с остальной частью системы, если это имеет значение. (В чьей-то настольной системе это, вероятно, довольно важно. В сетке с несколькими тысячами ЦП выделил этой задаче, Вы особенно не хотите играть по правилам, Вы просто хотите использовать каждый доступный такт).

Так для крупномасштабного материала HPC, да, Вы захотите, чтобы каждый поток остался на одном ядре, починенном. Но для большинства меньших задач, это не будет действительно иметь значения, и можно доверять планировщику ОС.

3
ответ дан jalf 28 November 2019 в 21:45
поделиться

Можно удостовериться, что оба потока планируются для тех же модулей выполнения путем предоставления им привязки процессора. Это может быть сделано или в окнах или в Unix через любого API (таким образом, программа может попросить его), или через интерфейсы администрирования (таким образом, администратор может установить его). Например, в WinXP можно использовать Диспетчер задач для ограничения, на каком логическом процессоре (процессорах) процесс может выполниться.

Иначе, планирование будет чрезвычайно случайно, и можно ожидать 25%-е использование на каждом логическом процессоре.

2
ответ дан sk. 28 November 2019 в 21:45
поделиться

Я не знаю о других платформах, но в случае Intel, они публикуют много из информация о поточной обработке на их Сеть Intel Software . У них также есть бесплатная новостная рассылка (Отправка Intel Software), Вы можете подписаться по электронной почте и имели много таких статей в последнее время.

1
ответ дан Jim Anderson 28 November 2019 в 21:45
поделиться

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

Я написал простую программу на C #, запускающую два потока. На моем четырехъядерном компьютере с Windows 7 я увидел несколько удивительных результатов.

Когда я не устанавливал привязку, Windows распределяла рабочую нагрузку двух потоков по всем четырем ядрам. Закомментированы две строки кода - одна, которая связывает поток с ЦП, а вторая предлагает идеальный ЦП. Предложение казалось безрезультатным, но установка сходства потоков заставляла Windows запускать каждый поток на своем собственном ядре.

Чтобы получить наилучшие результаты, скомпилируйте этот код с помощью свободно доступного компилятора csc.exe, который поставляется с клиентом .NET Framework 4.0, и запустите его на машине с несколькими ядрами. С закомментированной строкой соответствия процессоров диспетчер задач показал, что потоки распределены по всем четырем ядрам, каждое из которых работает примерно на 50%. При установленном сродстве два потока максимально использовали два ядра на 100%, а два других ядра работали в режиме ожидания (это то, что я ожидал увидеть перед тем, как запустить этот тест).

РЕДАКТИРОВАТЬ: Сначала я обнаружил некоторые различия в производительности этих двух конфигураций. Однако мне не удалось воспроизвести их, поэтому я отредактировал этот пост, чтобы отразить это. Мне все еще показалось интересным сходство потоков, поскольку это было не то, что я ожидал.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

class Program
{
    [DllImport("kernel32")]
    static extern int GetCurrentThreadId();

    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => ThreadFunc(1));
        Task task2 = Task.Factory.StartNew(() => ThreadFunc(2));
        Stopwatch time = Stopwatch.StartNew();
        Task.WaitAll(task1, task2);
        Console.WriteLine(time.Elapsed);
    }

    static void ThreadFunc(int cpu)
    {
        int cur = GetCurrentThreadId();
        var me = Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Where(t => t.Id == cur).Single();
        //me.ProcessorAffinity = (IntPtr)cpu;     //using this line of code binds a thread to each core
        //me.IdealProcessor = cpu;                //seems to have no effect

        //do some CPU / memory bound work
        List<int> ls = new List<int>();
        ls.Add(10);
        for (int j = 1; j != 30000; ++j)
        {
            ls.Add((int)ls.Average());
        }
    }
}
5
ответ дан 28 November 2019 в 21:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: