Разъедините программы, используя очереди - PullRequest
9 голосов
/ 04 января 2012

В своем выступлении на отметке 54:53 Рич Хики говорит об использовании очередей в качестве средства для отделения зависимых частей программы. Можете ли вы дать мне пример того, как отделить следующий фрагмент псевдокода Java для улучшения его дизайна и / или гибкости:

// Warning: Java-pseudo-code ahead
class Job {
    public void doRun(A a) {
        saveObjectToDatabase(a);

        B b = computeB(a);
        saveObjectToDatabase(b);

        C c = computeC(b);
        logToFile(c);
    }
}

saveObjectToDatabase и saveObjectToDatabase можно рассматривать как метод с побочными эффектами, тогда как выходные данные computeB и computeC зависят только от a.

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

Ответы [ 4 ]

3 голосов
/ 04 января 2012

Ну, это не очень хороший пример, но (в самом простом дизайне) у вас в основном было бы две очереди, и (в зависимости от количества задействованных данных) вы могли бы опустить базу данных.

Первый процесс получает ваши a объекты из «внешнего мира» и помещает их в очередь 1. Очередной процесс удаляет объекты из очереди 1, выполняет computeB и помещает результаты в очередь 2. Третийпроцесс будет исключать объекты из очереди 2, выполнять computeC и регистрировать результат или что-то в этом роде.

В зависимости, как я уже сказал, от количества задействованных данных (и, возможно, нескольких других факторов) «объекты»передаваемые в очереди могут быть вашими фактическими объектами a и b или просто токенами / ключами для поиска данных в базе данных.

Сами очереди могут быть реализованы несколькими способами.Можно реализовать очередь с базой данных, например, хотя детали становятся немного запутанными.«Процессы» могут быть задачами Java внутри одного процесса Java или могут быть отдельными процессами ОС, возможно, даже на отдельных машинах.

Когда вы используете «каналы» в Unix, вы эффективно используете очереди таким образом.

1 голос
/ 04 января 2012

Это именно тот принцип, который используется библиотекой Java, которую я использую.Идея состоит в том, чтобы компоненты были назначены для отдельных задач в программах (регистратор - прекрасный пример).Теперь каждый компонент должен работать независимо от других, либо как поток, либо как обработчик событий.

В случае событий, управляемых событиями, каждый компонент уведомляет, какие типы событий \ сообщений он хочет прослушивать.У вас есть диспетчер, который собирает входящие сообщения и вставляет их в очередь получателей.Получатель обрабатывает и в итоге генерирует новые сообщения.И т.д ...

В вашем случае, что-то вроде этого:

class SaveObjectHandler{
//
void handle(Event e, Object o){
  if(e instanceof SaveEvent)
      saveObjectToDatabase(o);
}

};

class TransformObject{
//
 void handle(Event e,Object o){
   if(e instanceof TransformEvent){
      B result = compute(o);
      send(new SaveEvent(),result)
   }

 }

};

class Logger{

   void handle(Event e, Object o){
      if(o instanceof B)
        //perform computeC
        logEvent((B)o);
   }

};

};

Библиотека, о которой идет речь SEDA .

0 голосов
/ 17 мая 2016

Ради полноты, я хотел бы добавить больше информации к ответу Hot Licks:

Я провел дополнительные исследования по этой теме и, наконец, пришел к выводу, что распутываниеметод это путь.Я буду использовать терминологию kafka производителей / потребителей / тем.Для получения дополнительной информации см. Журнал: Что должен знать каждый разработчик программного обеспечения об объединяющей абстракции данных в реальном времени и, в частности, этот график:

enter image description here

Что касается моего конкретного вопроса о приведенном примере, есть два способа его решения:

Решение 1

  • Потребитель 1:
    • использовать из темы a
    • сохранить в базе данных.
  • Потребитель 2:
    • использовать из темы a
    • вычислить b
    • сохранить в базе данных.
  • Потребитель 3: использовать из темы a
    • вычислить b
    • вычислить c
    • сохранить в базе данных

Недостатком является вычисление b дважды .В псевдокоде:

class ConsumerA  {
    public void consume(A a) {
        saveObjectToDatabase(a);
    }
}

class ConsumerB  {
    public void consume(A a) {
        B b = computeB(a);
        saveObjectToDatabase(b);
    }
}

class ConsumerLog  {
    public void consume(A a) {
        B b = computeB(a);
        C c = computeC(b);
        logToFile(c);
    }
}

Решение 2

  • Потребитель 1:
    • потребляет из темы a
    • сохранить в базе данных.
  • Потребитель 2:
    • использовать из темы a
    • вычислить b, сохранить в базе данных
    • опубликовать b в отдельной теме b.
  • Потребитель 3:
    • использовать из темы b
    • вычислить c
    • logToFile c

В псевдокоде:

class ConsumerA  {
    public void consume(A a) {
        saveObjectToDatabase(a);
    }
}

class ConsumerB  {
    public void consume(A a) {
        B b = computeB(a);
        saveObjectToDatabase(b);
        publish(b); // republish computed information to another topic b
    }
}

class ConsumerLog  {
    public void consume(B b) {
        C c = computeC(b);
        logToFile(c);
    }
}
0 голосов
/ 04 января 2012

Боюсь, что с методами saveObject, имеющими побочный эффект, вы не можете отделить его хорошо или, по крайней мере, не легко.

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

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