LINUX.ORG.RU

Разделяемая память в проекте

 


0

3

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

ДАНО: есть класс, который является своего рода средством организации вычислительного процесса, в нем могут выполняться разные сущности - юниты (все наследованы от Unit). Сам класс помимо предоставления средств регистрации, запуска, останова (и т.д.) юнитов еще инициализирует некоторую плату. Соответственно юниты через главный класс работают с различными сервисами платы. Главный класс содержит в себе реализацию паттерна «Одиночка». Так же базовый класс может назначить выполнение юнита в конкретном потоке, а может назначит его работу в своем потоке

Пример:

class A(Unit):
  def init(self):
    self.base = BASE()  

  # работает с сервисом А через self.base

class B(Unit):
  def init(self):
    self.base = BASE()

  # работает с сервисом Б через self.base

...

class BASE(object):
  def __new__(cls, *args, **kwargs):
    if cls.instance is None:
      cls.instance = super(BASE, cls).__new__(cls)
    return cls.instance

  def __init__(self):
    # инициализация платы
    self.plata = self.plata_init() # здесь поднимается плата ...

    # конект к БД
    self.db = self.connect_db()

    ...

Иногда требуется следующее, предположим сервис Б прислал юниту B сообщение, что обновился статус. Такое событие должно быть отправлено на сервер, и, чтобы в потоке юнита сама отправка не выполнялась, передается задание в task_manager (он тоже юнит и тоже одиночка) task_manager изначально порождал отдельный поток и создавал очередь, поток читал из очереди и создавал задания (опять же юниты, которые тоже могут пользоваться self.base из базового класса), однако из-за такой задницы как GIL, такие процедуры жутко тормозят работу базового класса и основных юнитов (таких как А и B). Я хотел было попробовать модуль multiprocessing, и через очередь передавать обработку заданий в дочерний процесс (хоть там GIL не подпортит мне жизнь), но в один момент времени с платой может работать только один процесс - значит надо базовый класс поместить в shared memory, но правильно это сделать у меня не получилось, подскажите советом друзья. Рассмотрю концептуально другие решения, заранее спасибо

значит надо базовый класс поместить в shared memory, но правильно это сделать у меня не получилось

в CPython это невозможно. Можно что-то поискать на предмет размещения бинарных данных в разделяемой памяти и как-то через них работать. Но это в питоне будет крайне геморно.

Рассмотрю концептуально другие решения, заранее спасибо

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

mashina ★★★★★ ()

из-за такой задницы как GIL, такие процедуры жутко тормозят работу базового класса и основных юнитов (таких как А и B)

Что значит тормозят? У тебя питонопрога выжирает целиком ядро проца? Какая версия питона?

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

версия 2.7 дело в том, что такие события происходят очень часто, в секунду может штук 5 прилететь, и каждое событие проходит обработку в несколько этапов (чтение данных из БД, формирование новых пакетов и т.д.). Есть некоторый мониторинг (программа нашего клиента), который отображает текущее состояние события и его этап обработки в реалтайм. Одни клиенты желают получать эту инфу по http, другие согласны на tcp (м.б. появятся новые клиенты с новыми потребностями). Проблема в том, что сейчас, пока выполняется тред task_manager (из-за GIL другие потоки будут заблокированы) обработка события приостанавливается... А теперь представьте что у нас, к примеру, 1000 клиентов... вот здесь и возникают тормоза. Поэтому и решено было сделать отдельных процесс, который будет выполнять такие задачи...

energyclab ()
Ответ на: комментарий от energyclab

все это прекрасно, но зачем клиентов обслуживать в том же процессе?

anonymous ()
Ответ на: комментарий от anonymous

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

energyclab ()

потоки можно заменить на процессы ?

kto_tama ★★★★★ ()

значит надо базовый класс поместить в shared memory, но правильно это сделать у меня не получилось, подскажите советом друзья

данные между процессами можно передать использую pickle (сериализация), но у него есть некоторые особенности - например, если объект содержит переменные файловых дескрипторов/сокетов, то такой объект не поддается сериализации.

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

Deleted ()
Ответ на: комментарий от energyclab

пока выполняется тред task_manager (из-за GIL другие потоки будут заблокированы) обработка события приостанавливается...

GIL не так работает. GIL это способ мультиплексирования тредов. Т.е., скажем, 100 раз в секунду идёт переключение нитей. Если у вас при обработке одной нити остальные блокируются то у вас проблема в коде. Я про проц спросил не просто так. Если оно не выжирает одно ядро проца целиком (или около того) то GIL вам не мешает.

true_admin ★★★★★ ()
Ответ на: комментарий от energyclab

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

Уральский в треде?

Побуду вангой. Все клиенты пытаются снять свежие данные с одной железяки? Или данные все же попадают в какое-то хранилище и уже оттуда раздаются?

anonymous ()
Ответ на: комментарий от Deleted

У меня собственно сейчас и вылезает ошибка

<class 'cPickle.PicklingError'> Can't pickle <type 'thread.lock'>: attribute lookup thread.lock failed


И это понятно почему...
Мне сейчас для решения проблемы достаточно организовать асинхронный обмен между двумя процессами следующим образом:
родительский процесс (РП) создает дочерний (ДП). Объект РП живет теперь пока на него есть ссылка, чтобы обратиться к ДП есть метод add_task(...): ... кладем данные в очередь ДП. В свое время в ДП в цикле читается очередь и, если поступают данные, он запускает их обработчиков, после чего снова читает очередь. Когда обработчик заканчивает выполнение, он присылает ДП сообщение, что задача выполнена, теперь ДП каким то образом должен сделать так, чтобы РП об этом узнал, идеальным бы было решение аля-сигнал, чтобы у РП по наступлению этого сигнала вызвался какой-нибудь хендлер, но я не знаю как это сделать
energyclab ()
Ответ на: комментарий от true_admin

Если у вас при обработке одной нити остальные блокируются то у вас проблема в коде

У меня потоки не блокируются, просто GIL не позволит в единицу времени выполнять более одного потока...

energyclab ()
Ответ на: комментарий от energyclab

У меня собственно сейчас и вылезает ошибка

Значит ты что-то делаешь не то. Прочитай ещё раз доки и юзай multiprocessing.Lock итп.

GIL не позволит в единицу времени выполнять более одного потока...

Ты упорно игнорируешь вопрос о том какова текущая нагрузка. У тебя действительно всё в проц упирается?

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

У тебя действительно всё в проц упирается?

удваиваю

Deleted ()
Ответ на: комментарий от energyclab

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

anonymous ()

Рассмотрю концептуально другие решения, заранее спасибо

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

arkhnchul ★★ ()

Рассмотрю концептуально другие решения, заранее спасибо

Начни с формулировки задачи. Пока что ты сформулировал (неработающее и переусложненное) решение.

tailgunner ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.