Я столкнулся с незначительной проблемой HPC после запуска некоторых тестов в архитектуре nehalem 80core (160HT) с DRAM 2Tb:
Сервер с более чем двумя сокетами начинает много останавливаться (задержка), так как каждый поток начинает запрашивать информацию об объектах в "неправильном" сокете, то есть запросы идут из потока, который работает с некоторыми объектами в одном сокете для получения информации, которая на самом деле находится в DRAM на другом сокете.
Ядро появляется на 100%, хотя я знаю, что они ждут, когда удаленный сокет вернет запрос.
Поскольку большая часть кода выполняется асинхронно, гораздо проще переписать код, поэтому я могу просто анализировать сообщения из потоков на одном сокете, чтобы потоки были другими (без блокировки ожидания). Кроме того, я хочу блокировать каждый поток в пулах памяти, поэтому я могу обновлять объекты, а не тратить время (~ 30%) на сборщик мусора.
Следовательно, вопрос:
Как связать потоки с ядрами с предопределенными объектами пула памяти в Python?
Немного больше контекста:
У Python нет проблем с запуском multicore, когда вы ставите ZeroMQ посередине и создаете искусство из передачи сообщений между пулом памяти, управляемым каждым ZMQworker. На ZMQ 8M msg/second это внутреннее обновление объектов занимает больше времени, чем трубопровод может быть заполнен. Все это описано здесь: http://zguide.zeromq.org/page:all#Chapter-Sockets-and-Patterns
Итак, с небольшим упрощением, я запускаю 80 ZMQworkerprocesses и 1 ZMQrouter и загружаю контекст с большим роем объектов (на самом деле 584 миллиона объектов). Из этой "начальной точки" объекты должны взаимодействовать для завершения вычисления.
Это идея:
- Если "объект X" должен взаимодействовать с "объектом Y" и доступен в локальный пул памяти в python-потоке, то взаимодействие следует делать напрямую.
- Если "Объект Y" НЕ доступен в одном пуле, то я хочу, чтобы он отправьте сообщение через ZMQrouter и позвольте маршрутизатору возвращать ответ в какой-то более поздний момент времени. Моя архитектура не блокирует, так что то, что происходит в конкретном потоке python, продолжается, не дожидаясь ответа zmqRouters. Даже для объектов в одном и том же сокете, но в другом ядре, я предпочел бы НЕ взаимодействовать, поскольку я предпочитаю иметь чистые обмены сообщениями вместо того, чтобы иметь 2 потока, управляющих одним и тем же объектом памяти.
Для этого мне нужно знать:
- Как определить, какой сокет - данный процесс python (thread) продолжается.
- как назначить пул памяти на этом конкретном сокете процессу python (некоторый предел malloc или аналогичный, чтобы сумма пулов памяти не пустила пул памяти из одного сокета в другой).
- Вещи, о которых я не думал.
Но я не могу найти ссылки в документах python о том, как это сделать и на google. Я должен искать неправильную вещь.
Update:
В отношении вопроса "зачем использовать ZeroMQ для архитектуры MPI?", пожалуйста, прочитайте поток: Распространение против MPI vs zeromq?, поскольку приложение, над которым я работаю, предназначенный для распределенного развертывания, хотя он протестирован на архитектуре, где MPI более подходит.
Обновление 2:
Относительно вопроса:
"Как связать потоки с ядрами с предопределенными пулами памяти в Python (3)" ответ находится в psutils:
>>> import psutil
>>> psutil.cpu_count()
4
>>> p = psutil.Process()
>>> p.cpu_affinity() # get
[0, 1, 2, 3]
>>> p.cpu_affinity([0]) # set; from now on, this process will run on CPU #0 only
>>> p.cpu_affinity()
[0]
>>>
>>> # reset affinity against all CPUs
>>> all_cpus = list(range(psutil.cpu_count()))
>>> p.cpu_affinity(all_cpus)
>>>
Работник может быть привязан к ядру, в котором NUMA может быть эффективно использована (найдите свой тип процессора, чтобы убедиться, что это NUMA-архитектура!)
Второй элемент - это определение пула памяти. Это можно сделать с помощью psutils или библиотека ресурсов: