Совместное использование памяти между потоками? - PullRequest
2 голосов
/ 22 сентября 2009

У меня есть приложение, которое обрабатывает несколько потоков из очереди todo. Я не имею никакого влияния на то, что попадает в очередь и в каком порядке (она подается внешним пользователем). Один рабочий элемент из очереди может занять от нескольких секунд до нескольких часов времени выполнения и не должен прерываться во время обработки. Кроме того, один рабочий элемент может занимать от нескольких мегабайт до примерно 2 ГБ памяти. Потребление памяти - моя проблема. Я работаю как 64-битный процесс на 8 ГБ машине с 8 параллельными потоками. Если каждый из них одновременно сталкивается с наихудшим рабочим элементом, мне не хватает памяти. Мне интересно, как лучше обойти это.

  1. планируйте консервативно и выполняйте только 4 потока. Худший случай больше не должен быть проблемой, но мы тратим много времени на параллелизм, делая средний случай намного медленнее.
  2. заставляет каждый поток проверять доступную память (или, скорее, общий объем выделенной памяти для всех потоков) перед началом работы с новым элементом. Запускать только тогда, когда осталось более 2 ГБ памяти. Периодически проверяйте, надеясь, что другие потоки закончат свою память, и мы можем начать в конце концов.
  3. попытайтесь предсказать, сколько элементов памяти из очереди потребуется (трудно), и составьте соответствующий план. Мы можем изменить порядок очереди (переопределение выбора пользователя) или просто настроить количество запущенных рабочих потоков.
  4. больше идей?

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

С уважением,

Sören

Ответы [ 3 ]

3 голосов
/ 22 сентября 2009

Таким образом, текущее использование памяти в худшем случае составляет 16 ГБ. Имея только 8 ГБ оперативной памяти, вам повезет, если у вас останется 6 или 7 ГБ памяти после того, как ОС и системные процессы получат свою долю. Таким образом, в среднем вы уже будете загружать память в умеренно загруженной системе. Сколько ядер у машины? У вас есть 8 рабочих потоков, потому что это 8-ядерный компьютер?

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

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

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

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

Тогда есть «увеличение доступной памяти». С точки зрения цены / производительности, вы должны серьезно подумать просто о покупке большего количества оперативной памяти. Иногда инвестиции в большее количество оборудования обходятся дешевле, чем время разработки, чтобы достичь того же конечного результата. Например, вы могли бы поместить 32 ГБ ОЗУ на несколько сотен долларов, и это сразу улучшило бы производительность, не добавляя сложности решению. При снижении производительности вы можете профилировать приложение, чтобы увидеть, где вы можете сделать программное обеспечение более эффективным.

1 голос
/ 14 октября 2009

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

Спасибо за все предложения!

Sören
0 голосов
/ 22 сентября 2009

Сложно предложить решения, не зная точно, что вы делаете, но как насчет рассмотрения:

  1. Проверьте, может ли ваш алгоритм обработки получить доступ к данным в небольших разделах без загрузки всего рабочего элемента в память.
  2. Рассмотрите возможность разработки решения на основе услуг, чтобы работа выполнялась другим процессом (возможно, веб-службой). Таким образом, вы можете масштабировать решение для работы на нескольких серверах, возможно, используя распределитель нагрузки для распределения работы.
  3. Сохраняете ли вы входящие рабочие элементы на диск перед их обработкой? В противном случае они, вероятно, должны быть в любом случае, особенно, если процессору до них доходит какое-то время.
  4. Пропорционально ли использование памяти размеру входящего рабочего элемента или иным образом легко рассчитать? Знание этого поможет решить, как планировать обработку.

Надеюсь, это поможет?!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...