Что означают термины «связанный с процессором» и «связанный с вводом / выводом»?


Ответы:


452

Это довольно интуитивно понятно:

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

Программа связана с вводом / выводом, если она будет работать быстрее, если подсистема ввода / вывода будет быстрее. Какая именно система ввода / вывода подразумевается, может варьироваться; Я обычно ассоциирую это с диском, но, конечно, сеть или общение в целом тоже распространены. Программа, которая просматривает огромный файл для некоторых данных, может быть привязана к вводу / выводу, поскольку узким местом является чтение данных с диска (на самом деле, этот пример, возможно, является старомодным в наши дни с сотнями МБ / с). из SSD).


Как это связано с пониманием HTTP-коммуникации на мобильном устройстве? Я видел всплеск использования процессора при использовании операций java.nio .
Игорь Ганапольский

Ввод / вывод - это «вход / выход».
Товарищ Че

247

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

Ограничение ввода / вывода означает, что скорость, с которой происходит процесс, ограничена скоростью подсистемы ввода / вывода. Задача, которая обрабатывает данные с диска, например, подсчет количества строк в файле, скорее всего, связана с вводом / выводом.

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

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

Bound I / O будет медленнее, чем Bound Memory, будет медленнее, чем Cache Bound, будет медленнее, чем CPU Bound.

Решение быть связанным с вводом / выводом не обязательно, чтобы получить больше Памяти. В некоторых ситуациях алгоритм доступа может быть разработан с учетом ограничений ввода-вывода, памяти или кэша. См. Алгоритмы кеширования .


73

Многопоточность

В этом ответе я расскажу об одном важном случае использования различий между CPU и IO: при написании многопоточного кода.

Пример, связанный с вводом / выводом в ОЗУ: векторная сумма

Рассмотрим программу, которая суммирует все значения одного вектора:

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

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

Например, на моем Ubuntu 19.04, ноутбуке Lenovo ThinkPad P51 с процессором: ЦП Intel Core i7-7820HQ (4 ядра / 8 потоков), ОЗУ: 2x Samsung M471A2K43BB1-CRC (2x 16 ГБ). Я получаю следующие результаты:

введите описание изображения здесь

Сюжет данных .

Обратите внимание, что между прогонами есть большое расхождение. Но я не могу значительно увеличить размер массива, так как я уже на 8 ГБ, и у меня нет настроения для статистики по нескольким прогонам сегодня. Однако это выглядело как типичный прогон после многих ручных прогонов.

Код теста:

Я не знаю достаточно компьютерной архитектуры, чтобы полностью объяснить форму кривой, но ясно одно: вычисления не становятся в 8 раз быстрее, чем наивно ожидалось, потому что я использую все свои 8 потоков! По некоторым причинам, 2 и 3 потоки были оптимальными, а добавление большего просто замедляет процесс.

Сравните это с работой с привязкой к процессору, которая на самом деле работает в 8 раз быстрее: что означают 'real', 'user' и 'sys' в выводе time (1)?

Причина в том, что все процессоры совместно используют одну шину памяти, соединяющуюся с RAM:

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

поэтому узким местом становится шина памяти, а не процессор.

Это происходит потому, что добавление двух чисел занимает один цикл ЦП, а чтение памяти занимает около 100 циклов ЦП в аппаратном обеспечении 2016 года.

Таким образом, процессорная работа, выполняемая на байт входных данных, слишком мала, и мы называем это процессом, связанным с IO.

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

Например, обновление до более быстрой тактовой частоты процессора не будет очень полезным.

Другие примеры

  • Умножение матриц связано с использованием ОЗУ и графических процессоров. Вход содержит:

    2 * N**2
    

    номера, но:

    N ** 3
    

    умножения сделаны, и этого достаточно, чтобы распараллеливание стоило того для большого практического N.

    Вот почему существуют параллельные библиотеки умножения матриц ЦП, подобные следующим:

    Использование кэша имеет большое значение для скорости реализации. Посмотрите, например, этот пример сравнения дидактического графического процессора .

    Смотрите также:

  • Сеть является прототипом IO-связанного примера.

    Даже когда мы отправляем один байт данных, для достижения цели все равно требуется много времени.

    Распараллеливание небольших сетевых запросов, таких как HTTP-запросы, может значительно повысить производительность.

    Если сеть уже загружена (например, загружается торрент), распараллеливание может увеличить задержку (например, вы можете загрузить веб-страницу «одновременно»).

  • Фиктивная операция с привязкой к процессору C ++, которая принимает одно число и сильно его сокращает:

  • Похоже, что сортировка выполняется с использованием ЦП на основе следующего эксперимента: реализованы ли уже параллельные алгоритмы C ++ 17? который показал увеличение производительности в 4 раза для параллельной сортировки, но я хотел бы также получить более теоретическое подтверждение

Как узнать, связаны ли вы с процессором или IO

IO без ОЗУ привязан как диск, сеть:, ps auxтогда theck, если CPU% / 100 < n threads. Если да, вы привязаны к IO, например, блокирующие reads просто ждут данных, и планировщик пропускает этот процесс. Затем используйте другие инструменты, например, sudo iotopчтобы решить, какой именно IO является проблемой.

Или, если выполнение выполняется быстро и вы параметризуете количество потоков, вы можете легко увидеть, timeчто производительность увеличивается по мере увеличения количества потоков для работы с привязкой к ЦП: что означают «реальные», «пользовательские» и «sys» в выход времени (1)?

Ограничение RAM-IO: сложнее сказать, так как время ожидания RAM включено в CPU%измерения, см. Также:

Некоторые варианты:

  • Intel Advisor Roofline (не бесплатно): https://software.intel.com/en-us/articles/intel-advisor-roofline ( архив ). «Диаграмма Roofline - это визуальное представление производительности приложений в отношении аппаратных ограничений, включая пропускную способность памяти и вычислительные пики. "

Графические процессоры

У графических процессоров есть узкое место ввода-вывода при первой передаче входных данных из обычной оперативно-читаемой памяти ОЗУ в графический процессор.

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

Однако, как только данные передаются в графический процессор, он может работать с этими байтами быстрее, чем процессор, потому что графический процессор:

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

  • использует параллелизм данных и жертвует задержкой, просто пропуская любые данные, которые не готовы к немедленной обработке.

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

Поэтому графический процессор может быть быстрее центрального процессора, если ваше приложение:

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

Эти варианты дизайна изначально были нацелены на применение 3D-рендеринга, основные шаги которого приведены в разделе Что такое шейдеры в OpenGL и для чего они нам нужны?

  • вершинный шейдер: умножение набора векторов 1х4 на матрицу 4х4
  • фрагментный шейдер: рассчитать цвет каждого пикселя треугольника на основе его относительного положения в треугольнике

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

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

Смотрите также:

CPython Global Intepreter Lock (GIL)

В качестве краткого примера я хочу указать на Python Global Lock Interpreter (GIL): что такое глобальная блокировка интерпретатора (GIL) в CPython?

Эта деталь реализации CPython не позволяет нескольким потокам Python эффективно использовать работу с процессором. Документы CPython говорят:

Детали реализации CPython: В CPython из-за Глобальной блокировки интерпретатора только один поток может выполнять код Python одновременно (даже если некоторые ориентированные на производительность библиотеки могут преодолеть это ограничение). Если вы хотите, чтобы ваше приложение более эффективно использовало вычислительные ресурсы многоядерных машин, рекомендуется использовать multiprocessingили concurrent.futures.ProcessPoolExecutor. Тем не менее, многопоточность по-прежнему является подходящей моделью, если вы хотите запустить несколько задач, связанных с вводом / выводом одновременно.

Таким образом, здесь у нас есть пример, когда содержимое, связанное с процессором, не подходит, а ограничение ввода-вывода.


1
Чувак, как тебе удается быть таким компетентным и писать, как этот?
Микаил Абдуллаев

1
@MikayilAbdullayev спасибо! Я склонен отвечать только на «важные вопросы» и возвращаюсь к ним снова и снова, изучая новые важные материалы.
Сиро Сантилли 法轮功 冠状 病 六四 事件 法轮功

31

ЦП означает , что программа упираются в CPU, или центрального блока обработки данных , в то время ввода / вывода связанных средством программа упираются ввода / вывода или ввода / вывода, такие как чтение или запись на диск, сеть и т.д.

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

[Под «узким местом» я подразумеваю то, что заставляет вашу программу работать медленнее, чем это было бы в противном случае.]


22

Еще один способ выразить ту же идею:

  • Если ускорение процессора не ускоряет вашу программу, это может быть связано с вводом / выводом .

  • Если ускорение ввода-вывода (например, с использованием более быстрого диска) не помогает, возможно, ваша программа связана с процессором.

(Я использовал «может быть», потому что вам нужно учитывать другие ресурсы. Одним из примеров является память).


11

Когда ваша программа ожидает ввода-вывода (т. Е. Чтение / запись на диск или чтение / запись по сети и т. Д.), Процессор может выполнять другие задачи, даже если ваша программа остановлена. Скорость вашей программы будет в основном зависеть от того, насколько быстро может произойти ввод-вывод, и если вы хотите ускорить ее, вам нужно будет ускорить ввод-вывод.

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

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


6

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

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


6

Процессы, связанные с вводом-выводом: тратите больше времени на ввод-вывод, чем на вычисления, много коротких циклов ЦП. Процессы, связанные с процессором: тратить больше времени на вычисления, несколько очень длинных циклов процессора


2

Посмотрите, что говорит Microsoft.

Ядром асинхронного программирования являются объекты Task и Task, которые моделируют асинхронные операции. Они поддерживаются ключевыми словами async и await. Модель довольно проста в большинстве случаев:

  • Для кода, связанного с I / O, вы ожидаете операцию, которая возвращает Task или Task внутри асинхронного метода.

  • Для кода с привязкой к ЦП вы ожидаете операцию, которая запускается в фоновом потоке с помощью метода Task.Run.

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

Пример ввода-вывода: загрузка данных из веб-службы

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

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

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

Приведенные выше примеры показали, как вы можете использовать async и await для работы с I / O и CPU. Это ключ, который вы можете определить, когда работа, которую вам нужно выполнить, связана с вводом-выводом или с процессором, потому что это может сильно повлиять на производительность вашего кода и потенциально может привести к неправильному использованию определенных конструкций.

Вот два вопроса, которые вы должны задать, прежде чем писать какой-либо код:

Будет ли ваш код чего-то «ждать», например, данные из базы данных?

  • Если ваш ответ «да», то ваша работа связана с вводом / выводом.

Будет ли ваш код выполнять очень дорогие вычисления?

  • Если вы ответили «да», то ваша работа связана с процессором.

Если ваша работа связана с вводом / выводом, используйте async и ожидайте без Task.Run . Вы не должны использовать Task Parallel Library. Причина этого изложена в статье Async in Depth .

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


2

Приложение привязано к ЦП, когда производительность арифметической / логической / с плавающей запятой (A / L / FP) во время выполнения в основном близка к теоретической пиковой производительности процессора (данные, предоставленные производителем и определяемые характеристиками процессор: количество ядер, частота, регистры, ALU, FPU и т. д.).

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

Если вы хотите приблизиться к пиковой производительности ЦП, стратегия может заключаться в том, чтобы попытаться повторно использовать большую часть данных в кэш-памяти, чтобы избежать запроса данных из основной памяти. Алгоритм, который использует эту особенность, является умножением матрицы на матрицу (если обе матрицы могут быть сохранены в кэш-памяти). Это происходит потому, что если матрицы имеют размер, n x nто вам нужно работать с 2 n^3операциями, используя только 2 n^2числа FP. С другой стороны, добавление матрицы, например, является менее связанным с ЦП или более связанным с памятью приложением, чем умножение матрицы, поскольку для этого требуются только n^2FLOP с одинаковыми данными.

На следующем рисунке показаны FLOP, полученные с помощью наивных алгоритмов сложения матриц и умножения матриц в Intel i5-9300H:

Сравнение FLOP между матричным сложением и матричным умножением

Обратите внимание, что, как и ожидалось, производительность умножения матриц больше, чем сложение матриц Эти результаты могут быть воспроизведены путем запуска test/gemmи test/mataddдоступны в этом хранилище .

Я предлагаю также посмотреть видео, данное Дж. Донгаррой об этом эффекте.


1

Связанный процесс ввода / вывода: - Если большая часть времени жизни процесса проводится в состоянии ввода / вывода, то этот процесс является процессом, связанным с вводом / выводом. Пример: -calculator, Internet Explorer

Процесс, связанный с процессором: - Если большая часть срока службы процессируется в процессоре, то это процесс, связанный с процессором.


8
Как калькулятор будет процессом ввода-вывода? Конечно, это будет связано с процессором. Если ваш калькулятор тратит большую часть своего времени на доступ к сети или диску, то я бы предположил, что с ним что-то не так.
rickerbh

6
Я подумал, что пример калькулятора понятен: большую часть времени он ждет, пока пользователь нажмет кнопку, и, следовательно, ждет ввода / вывода.
psp

1
@psp прав, но пример калькулятора по-прежнему трудно воспринимать как ограниченный из-за его названия «калькулятор». Это означает, что основной целью программы является выполнение длинных вычислений ЦП, но если вы посмотрите на свой калькулятор на рабочем столе, он очень прост и выполняет вычисления, для выполнения которых требуются наносекунды. Таким образом, большую часть времени он ожидает пользовательского ввода, то есть ввода-вывода.
Калибр
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.