Почему однопоточный процесс выполняется на нескольких процессорах/ядрах?

Скажем, я запускаю простой однопоточный процесс, подобный приведенному ниже:

public class SirCountALot {
    public static void main(String[] args) {
        int count = 0;
        while (true) {
            count++;
        }
    }
}

(Это Java, потому что это то, с чем я знаком, но я подозреваю, что это не имеет большого значения)

У меня есть процессор i7 (4 ядра или 8 счетных гиперпотоков), и я запускаю 64-разрядную версию Windows 7, поэтому я запустил Sysinternals Process Explorer, чтобы посмотреть на использование ЦП, и, как ожидается, я вижу, что он использует около 20% всего доступного процессора.

Graph showing 20% CPU usage across all cores

Но когда я переключаю параметр, чтобы показать 1 график на процессор, я вижу, что вместо 1 из 4 "ядер", использование ЦП распространяется по всем ядрам:

Graph showing erratic CPU usage on each core totaling around 20% usage

Вместо этого я ожидал бы 1 core maxed out, но это происходит только тогда, когда я устанавливаю сродство к процессу к одному ядру.

Graph showing most of recent CPU usage to be confined to first core

Почему рабочая нагрузка распределяется по отдельным ядрам? Не будет ли разделение рабочей нагрузки на несколько ядер беспорядочно с кешированием или на другие штрафы за производительность?

Является ли это простой причиной предотвращения перегрева одного ядра? Или есть какая-то более глубокая причина?

Изменить: Я знаю, что операционная система отвечает за планирование, но я хочу знать, почему это "беспокоит". Разумеется, с наивной точки зрения, приклеивание (в основном *) однопоточного процесса до 1 ядра - это более простой и эффективный способ перехода?

* Я говорю в основном однопоточно, потому что здесь много ада, но только 2 из них делают что-то:

Screenshot showing number of threads from EclipseScreenshot showing number of threads in Process Explorer process properties

Ответ 1

ОС отвечает за планирование. Он может остановить поток и запустить его снова на другом CPU. Он будет делать это, даже если больше ничего не делает машина.

Процесс перемещается вокруг процессоров, потому что ОС не предполагает, что есть какая-либо причина продолжать выполнение потока на одном и том же ЦП каждый раз.

По этой причине я написал библиотеку для блокировки потоков в CPU, чтобы она не перемещалась и не прерывалась другими потоками. Это уменьшает время ожидания и повышает пропускную способность, но утомляет процессор для этого потока. Это работает для Linux, возможно, вы можете адаптировать его для Windows. https://github.com/peter-lawrey/Java-Thread-Affinity/wiki/Getting-started

Ответ 2

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

Таким образом, он будет вращать (уникальный/одиночный) поток от ядра к ядру.

И это может быть аргументом против попыток бороться с этим слишком сложно (особенно, поскольку на практике вы часто увидите улучшения, просто настроив/улучшив приложение в любом случае)