@hsc Хмм. Это очень похоже на события - стандартные объекты в библиотеках multithreading и multiprocessing. Опишу кратко:
Создается экземпляр класса Event. Затем его копия передается в виде аргумента воркеру.
У Event есть 2 состояния - нечто вроде True и False. По умолчанию он выключен (false). Притом изменение состояния экземпляра этого класса в одном из потоков/процессов повлечет мгновенное изменение состояния во всех других.
У него есть всего 4 метода:
1. is_set() - возвращает True и False соответственно состоянию события
2. set() - Устанавливает событию значение True
3. clear() - Устанавливает событию значение False
4. wait([timeout]) - Самое вкусное - приостановить работу процесса/потока до тех пор, пока значение флага не станет True. Таймаут необязателен, и, я думаю, его значение объяснять не нужно.
По сути это идеальный вариант. Но опять же все сводится к одному глобальному вопросу: как доставить экземпляр класса Event от воркера к обработчику?
По поводу wait-conditions. Я так понимаю это нечто похожее на Event, но все также требующее наличия одного и того же экземпляра в обоих модулях (воркере и обработчике). Поправьте, если я ошибаюсь.
И кстати. Может быть я сейчас скажу глупость, но тем не менее. Помните, существует глобальное пространство имен. Помню, что его можно использовать для констант/переменных. Но можно ли для объектов?
К сожалению не имею сейчас возможности проверить это на практике (по дороге домой). Если есть возможность - проверьте-отпишите. Может я вообще зря мучаюсь?
Если это не работает, то, вероятно, следует копаться в иерархии Django. Можно найти общий и для воркера и для обработчика родительский класс и попытаться создать в нем новое поле. Но слишком уж это заморочено.
@hsc Да, пожалуй то, что Вы описали - идеальный вариант. Только остается еще один момент.
Помните я писал про кнопку в веб-морде, по нажатию на которую должен срабатывать выход GPIO? Так вот. Крайне желательно, чтобы задержка между нажатием/срабатыванием была минимальна. Конечно же можно использовать цикл, который каждую секунду будет дергать ключ с редиса, но мне кажется это решение костыльным.
Второй вариант - забить в данном случае на демона и подать сигнал на GPIO напрямую из обработчика можно отметать сразу. Дело в том, что при инициализации ножки модулем GPIO создается исключительная блокировка, которая действует вплоть до выполнения GPIO.cleanup(), что в данном случае не приемлемо.
Собственно вопрос (надеюсь последний) звучит так: можно ли заставить redis/что нибудь подобное вызывать определенный метод определенного объекта?
По сути это не так важно, но все таки хочется сделать все идеально.
Даже если такого решения нет, то ничего страшного. В любом случае спасибо Вам за помощь.
@hsc Доброе утро. По поводу первого скажу, что я уже не раз работал с потоками/процессами. Соответственно я знаю, что к ним не нужно относиться как к объектам. Как вы и сказали, тот самый класс (его экземпляр) является дескриптором этого потока. Т.е. поток управляется при помощи очередей (Queue), с которыми и взаимодействуют другие объекты. То есть сам экземпляр - простой объект, работающий в том же потоке.
В принципе, то, что вы написали, способно решить поставленную передо мной задачу, но,если уж на то пошло, давайте я вкратце опишу суть приложения. Может найдется какое-нибудь более лаконичное решение нежели демон запущенный в новом процессе/потоке.
Необходимо заставить Raspberry Pi в определенные моменты дергать GPIO выход. Но все дело в том, что время указывается в веб-морде (для этого тут и Django). Соответственно необходимо сделать так, чтобы изменения вступали в силу здесь и сейчас.
Изначально я планировал сделать так:
1. Запускается вебсервер. Инициализируется Django. Создается экземпляр дескриптора демона.
2. При инициализации дескриптор стягивает текущее расписание с базы данных и запускает демона (передавая ему расписание и 2 объекта Queue в качестве атрибутов) в новом потоке.
3. Django завершает инициализацию. Вся эта система работает некоторое время. Затем в панель логинится пользователь. Он изменяет расписание.
4. После этого все изменения посредством ajax отправляются на сервер и обрабатываются Django.
5. Django сохраняет изменения в базе данных, а затем вызывает метод changeChedule(schedule) дескриптора демона.
6. Дескриптор, получив новое расписание применяет его (там просто стоит перебор в виде цикла for, который каждые несколько секунд проверяет текущее время. Соответственно перед каждым таким циклом демон проверяет, нет ли в очереди чего-нового)
7. Обработчик ajax запроса завершается и пользователь получает ответ в стиле "OK".
Ну помимо этого должно быть еще кое-что. Например отображение лога демона на странице управления или кнопки (там же) подачи сигнала вручную. Но все это уже мои заботы.
Я никак не могу понять, как осуществить пункт 5 не пересоздавая при этом демона. Видимо придется юзать redis.
Так речь не о взаимодействии между экземпляром класса и его методами. Мне нужно передать ссылку на экземпляр демона в другой экземпляр другого класса. Т.е. Демон запустился при инициализации django, а управляться должен из обработчиков определенных страниц. Ну скажем /save.
Нужно отталкиваться от особенностей django. Ну я не знаю, найти общий класс, задать ему поле в виде ссылки на демон...
По сути задача описана в вопросе. Просто подумайте, как бы Вы поступили на моем месте.