Используют ли потоки виртуальную память или реальную память?

10

Я пытался оптимизировать свой сервер Linux для обработки 10 000 потоков на процесс, в то время как сейчас он работает только с 382. Согласно этой статье, следующая формула используется для определения общего количества возможных потоков:

number of threads = total virtual memory / (stack size*1024*1024)

Это означает, что потоки хранят все свои данные в виртуальной памяти. Насколько мне известно, виртуальная память - это пространство подкачки на машине Linux, которая хранится на жестком диске, а не в ОЗУ или кеше.

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

Если да, то не влияет ли это на производительность? Можем ли мы повысить производительность, поместив их в оперативную память или кэш? Как?

Если нет, то как именно работают потоки?

Обновить:

Согласно бесполезному ответу , виртуальная память - это система, состоящая примерно из:

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

Таким образом, все, что находится в виртуальной памяти, в совокупности находится в ОЗУ (реальная память) и на жестком диске (файлы подкачки). И, как объясняет Джеймс в своем ответе, решение о Ram против HDD принимается Kernel с использованием таких алгоритмов, как LRU.

dragosrsupercool
источник
2
если ваш сервер не имеет 10000 процессоров / ядер, вы тратите время впустую.
@JarrodRoberson: Кто-нибудь, почему это?
dragosrsupercool
3
10000 потоков - это не хороший способ масштабирования, это хороший способ заставить сервер перейти на обход, более чем 1 поток на процессор или ядро ​​просто заставит контекст сервера переключаться и работать медленнее, а не быстрее.
В частности, когда вы говорите «пытаетесь оптимизировать мой сервер Linux» - что вы пытаетесь оптимизировать? Если это пропускная способность, то лучше использовать один поток на процессор с мультиплексированием и неблокирующим вводом / выводом.
бесполезно

Ответы:

12

Насколько мне известно, виртуальная память - это пространство подкачки на машине с Linux

Нет, виртуальная память - это система, состоящая примерно из:

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

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

Бесполезный
источник
Итак, мое предположение о виртуальной памяти было неверным. В любом случае, быстрый ответ на вопрос. Повлияет ли на производительность полностью загруженных макс потоков, если пространство SWAP больше ОЗУ?
dragosrsupercool
@dragosrsupercool: ваше пространство подкачки всегда будет больше, чем физическая память, в противном случае может потребоваться использование виртуальной памяти.
Брайан Оукли
1
@BryanOakley: Это не обязательно правда. Некоторые ОС выделяют страницу подкачки для каждой выделенной виртуальной страницы (т. Е. Размер свопа должен быть не меньше физического). Другие ОС выделяют страницу подкачки только тогда, когда необходимо переместить страницу из физической памяти (т. Е. Объем подкачки может быть меньше физической). Преимущество первого состоит в том, что если выделение завершается успешно, то замена этой памяти всегда успешна. Преимущество последнего состоит в том, что вам не нужно пессимистически выделять огромные файлы подкачки для учета относительно редких ситуаций.
mcmcc
1
@dragosrsupercool, производительность не будет зависеть от объема ОЗУ, подкачки или соотношения между ними, если у вас недостаточно ОЗУ и фактически выполняется подкачка. sar может рассказать о пейджинговой активности iirc (проверено: sar -Bв Linux).
бесполезно
@ Бесполезно: я хочу увеличить количество потоков, пока я полностью не использую оперативную память и не начинаю пейджинг.
dragosrsupercool
14

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

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

Виртуальные адреса организованы в блоки, называемые страницами (обычно это блоки 4096 или 8192 байта).

В любой момент времени каждый блок виртуальной памяти хранится где-то в реальной памяти или на диске в «пространстве подкачки», зарезервированном для этого.

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

Очевидно, что когда вся физическая память используется, если что-то выгружается, то нужно выгружать что-то еще, поэтому система ищет страницу «Наименее недавно использованная» и копирует ее на диск перед копированием запрошенной страницы.

В современных системах есть несколько оптимизаций и приемов, связанных с виртуальным хранилищем.

  • Адреса отображаются по принципу «на процесс», поэтому, например, все программы на C в Linux-системе запускают «основной» процесс с одного и того же адреса.
  • Это может позволить нескольким 32-разрядным процессам занимать и использовать на машине намного больше 4 ГБ, поскольку 32-разрядный виртуальный адрес может быть сопоставлен с реальным 64-разрядным адресом.
  • Когда процессы завершаются или память иным образом «освобождается», система просто помечает страницы как свободные, они никогда не копируются обратно на диск подкачки.
  • Точно так же, когда запрашивается новый блок памяти, система просто захватывает свободную страницу в реальной памяти, нет, происходит дисковый ввод-вывод.
  • Функции sleep и hibernate заставляют копировать всю память в пространство подкачки, чтобы все текущие процессы и текущее содержимое памяти можно было воссоздать при пробуждении.
Джеймс Андерсон
источник
3
«Все программы на C в Linux-модуле запускаются [main] по одному и тому же адресу», по-видимому, не принимают во внимание рандомизацию расположения адресного пространства. Это используется все больше и больше сегодня, чтобы помешать различным схемам атаки стека. Хороший ответ, иначе +1.
CVn
7

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

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

Итак, потоки будут использовать доступную память - какой бы она ни была доступна. Сколько потоков вы можете запустить, зависит от объема памяти и объема памяти, необходимого для каждого потока. Если поток использует кучу (не только стек), то ему нужно больше памяти, и в этом случае вы можете запустить меньше потоков.

BЈовић
источник
@VJonvic: +1 для объяснения основной темы.
dragosrsupercool
6

Простой ответ на ваш вопрос: они используют виртуальную память. все использует виртуальную память, за исключением нескольких процессов, связанных с ОС.

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

Брайан Оукли
источник
3

Виртуальная память - это ваша оперативная память плюс пространство подкачки. Виртуальный означает, что адрес, который видит ваша программа, отличается от адреса, который видит чип ОЗУ. Если вам нужен доступ к памяти в режиме подкачки, ОС сначала переместит ее в оперативную память. Если вы не хотите менять местами, просто отключите его. Если у вас достаточно оперативной памяти, она вам не нужна.

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

Карл Билефельдт
источник
Да, 10 000 - это слишком много, так как мой сервер - 32-битная одноядерная машина. На самом деле, потоки не являются общей вещью процессора. Они представляют собой потоки гусеничных лент, поэтому иногда им приходится ждать ответа сервера. Я хочу убедиться, что процессор полностью занят, но не перегружен или недогружен. Но я все еще не понимаю, как я могу узнать, является ли процессор свободным или полностью занятым. Есть какой-нибудь инструмент или команда?
dragosrsupercool
Я думаю, что вы можете получить эту информацию из topкоманды.
Карл Билефельдт
@KarlBieledeldt: да, это именно то, что я искал ... Еще один вопрос для продолжения: я просто пришел с идеей сканирования, что если кто-то как один поток может отправить запрос на URL-адреса, в то время как другой поток получает ответ сервера, я могу сохранить Высокая загрузка ЦП без использования слишком большого количества потоков. Это возможно? Как отправить запрос из одного потока при получении ответа в другом потоке?
dragosrsupercool
2

оптимизировать мой сервер Linux для обработки 10000 потоков на процесс

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

Читайте Операционные системы: Три Легких Части (свободно загружаемый учебник).

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

В Linux потоки и процессы очень похожи (поскольку оба могут быть созданы с помощью clone (2) ), и оба являются задачами, запланированными ядром. На самом деле планировщик ядра - это планирование задач, которые могут быть потоками внутри какого-либо многопоточного процесса или одного основного потока однопоточного процесса (в этом случае вы будете называть «процесс» этим единственным потоком) или потоков ядра. Вы, вероятно, не хотите иметь более тысячи планируемых задач в общей сложности на вашей настольной системе.

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

Виртуальное адресное пространство будет определенно Википедией , как

«набор диапазонов виртуальных адресов, которые операционная система делает доступными для процесса»

(но см. также этот ответ, объясняющий, что терминология не является универсальной, и в некоторой документации Microsoft используется другое и несовместимое определение).

В Linux proc (5) полезна для понимания виртуального адресного пространства некоторых процессов. Попробуйте оба
cat /proc/self/mapsи cat /proc/$$/mapsв терминале. Смотрите также это и pmap (1) & ps (1) & top (1) .

Все программы пользовательского пространства выполняются в каком-либо процессе и используют виртуальную память, поэтому каждый процесс имеет свое собственное виртуальное адресное пространство. Физическая ОЗУ - это ресурс, управляемый ядром Linux, и приложения не имеют прямого доступа к ОЗУ (кроме как с помощью mmap (2) -ing /dev/mem, см. Mem (4) ).

Таким образом, процесс не использует непосредственно RAM. Он использует виртуальную память и имеет собственное виртуальное адресное пространство. Ядро использует пейджинг для управления физической памяти страниц и обеспечивает виртуальное адресное пространство и процесс абстракции . В любое время (даже когда ваш процесс простаивает или когда он работает) ядро ​​может вывести на экран некоторые страницы (например, поменять их местами на диске). Ядро конфигурирует MMU (и обрабатывает исключения аппаратных исключений страницы в некотором обработчике прерываний , либо путем извлечения страницы с диска, либо путем передачи ошибки сегментации в процесс, см. Signal (7) )

Вы можете иметь зеленые потоки над системными потоками (но библиотеки зеленых потоков сложно реализовать и отладить). Посмотрите на goroutines, используемые в Go для причудливого примера. Смотрите также setcontext (3) .

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

Смотрите также -для Linux- fork (2) , clone (2) , mmap (2) , madvise (2) , posix_fadvise (2) , mlock (2) , execve (2) , учетные данные (7) , pthreads (7) , futex (7) , возможности (7) .

Василий Старынкевич
источник