Найти - Пользователи
Полная версия: Фреймворк для большого количества отдельных приложений
Начало » Python для экспертов » Фреймворк для большого количества отдельных приложений
1 2
alexte
Возникла задача, в которой есть сотня-другая очень малонагруженных приложений-сервисов,
которые общаются друг с другом и с приложениями на других серверах посредством, например, ZeroMQ (непринципиально).
Запускать столько приложений отдельно одновременно, боюсь никакого ОЗУ не хватит.
Обязательно нужно иметь возможность любое приложение останавливать, модифицировать код и снова запускать.
Привожу рисунок для лучшего понимания задачи. Что посоветуете?

doza_and
alexte
ZeroMQ (непринципиально).
Например в ZMQ сообщения могут вставать в очередь на обработку, обработчики при этом не обязаны быть в оперативной памяти. Диспетчер обработчиков может их подгружать после посылки им сообщений.

А самое простое решение просто сделать swap побольше. Все что не активно будет вытеснено на диск. Так что делать ничего не надо.

Вообще в древности были такие штуки https://ru.wikipedia.org/wiki/Overlay_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5). Но те времена давно прошли. Запустите вашу сотню приложений и покажите что вам не хватает памяти или не будет хватать с развитием системы.

Если приложения это код на питоне то имеет смысл не городить огород с zeromq а сделать динамический импорт плагинов в одно приложение. Обмен - greenlet/asyncio.
lorien
Если приложение жрёт 100мб, например. И их сотня-другя. То это 10-20гб. В чём проблема?
alexte
Проблема в том, что ОЗУ ограничено и сильно. Это миникомпьютеры на ARM всего с 1ГБ.
В принципе задача почти решена при помощи asyncio task. Разбираюсь с возможностью перезагрузки модулей “на лету”…
alexte
Решил. Что-то нарыл в инете, что-то дописал.

Вот основной модуль
import time
import asyncio
import functools
from threading import Thread, current_thread, Event
from concurrent.futures import Future
import importlib
import sys
class Apps(Thread):
    def __init__(self, start_event):
        Thread.__init__(self)
        self.loop = None
        self.tid = None
        self.event = start_event
    def run(self):
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.tid = current_thread()
        self.loop.call_soon(self.event.set)
        self.loop.run_forever()
    def stop(self):
        self.loop.call_soon_threadsafe(self.loop.stop)
    def add_task(self, coro):
        """this method should return a task object, that I
          can cancel, not a handle"""
        def _async_add(func, fut):
            try:
                ret = func()
                fut.set_result(ret)
            except Exception as e:
                fut.set_exception(e)
        f = functools.partial(asyncio.async, coro, loop=self.loop)
        if current_thread() == self.tid:
            return f() # We can call directly if we're not going between threads.
        else:
            # We're in a non-event loop thread so we use a Future
            # to get the task from the event loop thread once
            # it's ready.
            fut = Future()
            self.loop.call_soon_threadsafe(_async_add, f, fut)
            return fut.result()
    def cancel_task(self, task):
        self.loop.call_soon_threadsafe(task.cancel)
class Tasks:
    def __init__(self, module):
        self.module = module
        importlib.import_module(self.module)
        self.t = appl.add_task(sys.modules[self.module].tst1())
    def reload(self):
        appl.cancel_task(self.t)
        importlib.reload(sys.modules[self.module])
        self.t = appl.add_task(sys.modules[self.module].tst1())
    def cancel(self):
        appl.cancel_task(self.t)
event = Event()
appl = Apps(event)
appl.start()
event.wait()  # Let the loop's thread signal us, rather than sleeping
t1 = Tasks('appl1')
t2 = Tasks('appl2')
t3 = Tasks('appl3')
time.sleep(5)
t1.reload()
t2.reload()
time.sleep(5)
t1.cancel()
t2.cancel()
t3.cancel()
time.sleep(1)
appl.stop()

запускает подгружаемые модули appl1…3
import asyncio
@asyncio.coroutine
def tst1():
    i = 0
    while True:
        print('appl1... {0}'.format(i))
        i += 1
        yield from asyncio.sleep(1)
PooH
alexte
Возникла задача, в которой есть сотня-другая очень малонагруженных приложений-сервисов,которые общаются друг с другом и с приложениями на других серверах посредством, например, ZeroMQ
Может тупо по типу CGI: одно приложение, которое слушает очередь, запускает другие, передавая им параметры из очереди и собирая их выхлоп?
JOHN_16
alexte
расскажите что за конкретно микропк, название/модель ?
doza_and
t1 = Tasks('appl1')
t2 = Tasks('appl2')
t3 = Tasks('appl3')
time.sleep(5)
t1.reload()
t2.reload()
time.sleep(5)
t1.cancel()
t2.cancel()
t3.cancel()
time.sleep(1)
appl.stop()
Это некрасиво. Обычно сканируют папку с плагинами и все их пихают в приложение.
yield from asyncio.sleep(1)
Тут я просто не понял. Зачем time.sleep(5), sleep(1) Наверное нужно sleep(0). Если хотите запускать задачи по расписанию то на это есть https://docs.python.org/2/library/sched.html или его аналоги. А использовать sleep для ожидания завершения операций очень плохая практика. Неожиданно перестанет работать в тот момент когда вы уже забудете для чего все эти sleep
alexte
Код, приведенный ниже классов, - это просто маленький тест на создание приложений их перезагрузку и остановку. Если запустите, то увидите зачем там паузы.

JOHN_16
расскажите что за конкретно микропк, название/модель ?

Orange pi pc, с 1ГБ памяти и ценой 18 USD…
s0rg
supervisor?
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB