Разрабатывать этот алгоритм лучше?

Я работаю над гораздо более сложной версией этого (с движением транспортного средства в направлениях X и Y)

Я сделал этот пример, чтобы получить идеи о лучших способах достижения этого.

  • У меня есть транспортное средство, движущееся в направлении X со скоростью (24.5872 mps).
  • Я имитирую это, увеличивая значение X каждые 100 мс с помощью исполнителя (чтобы сохранить его положение X более точным и в реальном времени)
  • Через каждую секунду я отправляю сообщение другому процессу с значениями xMin и xMax строки, которую я только что рассмотрел.
  • Другой процесс будет отвечать сообщением JMS (как правило, мгновенно), говорящим мне прекратить, если в предыдущей области X была "Pothole" (Message callback msg to linkedblockqueue).

Проблема, с которой я столкнулся, - это часть "обычно мгновенно". Если я не получу ответ достаточно быстро, я думаю, что он сбросит все время моего алгоритма. Каков наилучший способ справиться с этой ситуацией?

Вот базовый код того, что я пытаюсь сделать:

public class Mover implements MessageHandler {

    private static final long CAR_UPDATE_RATE_IN_MS = 100;
    private static double currX = 0;
    private static double CONSTANT_SPEED_IN_MPS = 24.5872; // 55 mph
    private static double increment = CONSTANT_SPEED_IN_MPS / (1000 / CAR_UPDATE_RATE_IN_MS);
    static LinkedBlockingQueue<BaseMessage> messageQueue = new LinkedBlockingQueue<BaseMessage>(); // ms

    private static int incrementor = 0;

    public static void main(String[] args) {
        startMoverExecutor();
    }

    private static void startMoverExecutor() {

        ScheduledExecutorService mover = Executors.newSingleThreadScheduledExecutor();
        mover.scheduleAtFixedRate((new Runnable() {

            @Override
            public void run() {
                currX = incrementor * increment;

                if (incrementor % (1000 / CAR_UPDATE_RATE_IN_MS) == 0) {
                    System.out.println(currX);

                    sendMessage(currX - CONSTANT_SPEED_IN_MPS, currX);

                    // do something
                    try {
                        messageQueue.poll(1000, TimeUnit.MILLISECONDS);

                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
                incrementor++;
            }

        }), 0, CAR_UPDATE_RATE_IN_MS, TimeUnit.MILLISECONDS);

    }

    @Override
    public void handleMessage(BaseMessage msg) {
        messageQueue.add(msg);

    }

    protected static void sendMessage(double firstX, double secondX) {
        // sendMessage here

    }

}

Ответ 1

Я предлагаю изменения в вашем алгоритме выше, как показано на шагах ниже.

JMS Вызов другого процесса


1а. Начните с отправки текущей позиции vehical.

1b. Другой процесс будет отвечать сообщением JMS, содержащим список всех позиций "Поля отверстий" в видимой области вашего местоположения. Сохраните этот список "видимых позиций отверстий в отверстиях" на стороне клиента для использования в шагах ниже.

1в. Мы определяем видимую область как виртуальную соседнюю область, так что даже с (1-секундная задержка + сетевое отставание) вызова другого процесса с JMS движение вехи не должно пересекать эту область.

1г. После каждой секунды повторите шаги 1a и 1b и замените список позиций отверстий в горшках на стороне клиента относительно текущего положения вашего оборудования.

.

Наблюдатель за движением Vehical


2а. Внедрите шаблон наблюдателя, который может получать уведомления о передвижениях.

2b. Каждый раз, когда событие генерируется, наблюдатель будет проверять, совпадает ли позиция в вехе с одной из записей в списке видимых отверстий в канале, полученных на шаге 1b.

2в. Если матч найден, бинго! Вы должны остановить вех.

.

Движение вех


3a. Зарегистрировать шага-2a наблюдателя для наблюдения за движениями движения.

3b. Подождите, пока вы не получите по крайней мере первый список видимых отверстий в горшке с шага 1b.

3в. Начните перемещать вех, увеличивая значение X каждые 100 мс. Каждый раз, когда он перемещается, он должен уведомить наблюдателя step-2a.

.

Легенды ниже диаграммы:


o - Instance of each pot hole somewhere on map 
X - Moving vehical
. - Path followed by vehical
Circle - Visible area of the vehical driver
+---------------------------------------------+
|                                             |
|                    o                o       |
|    o                                        |
|                                             |
|                                             |
|                _.-''''`-._                  |
|    o         ,'           `.             o  |
|            ,'  o            `.              |
|           .'    .            `.             |
|           |      . .          |             |
|           |         .         |   o         |
|           |         X         |             |
|   o       \                o  /             |
|            \                 /              |
|             `.             ,'               |
|               `-._     _.-'                 |
|                   `''''                     |
|                                             |
|                  o                          |
|                                    o        |
|                                             |
|                                             |
|     o                        o              |
+---------------------------------------------+

Ответ 2

Если вы не используете систему в сетях и операционных системах, которые предоставляют гарантии в реальном времени, иногда будут задержки. Таким образом, вы должны иметь возможность обнаруживать эти задержки и решать, как реагировать - останавливается ли время для вашей стороны моделирования до тех пор, пока автомобиль не узнает, как карта разворачивается под ним? или время продолжает течь, но поздно опознанная выбоина появляется дальше по дороге, чем это было бы? или поздняя приходная выбоина, обнаруженная как поздняя и игнорируемая?

Я не слишком хорошо разбираюсь в текущем состоянии обмена сообщениями Java. Можете ли вы уточнить, блокируется ли messageQueue.poll? Если вы отправляете сообщение и затем блокируете ответ, возникает вопрос, почему вы не используете что-то синхронное, как вызов метода удаленному объекту, поскольку это, безусловно, поможет инфраструктуре в получении сообщений вам без промедления.

Ответ 3

Я бы сэкономил время вычисления currX вместе с позицией (currX)

В следующий раз, когда вы вычислите currX, вы увидите, сколько миллисекунд прошло с последнего раза (System.currMillisec() - lastCalc), умножьте это на скорость и добавьте в currX. Затем установите последнюю дату вычисления.

изменить: - Будьте осторожны с вашим устройством (постоянное имя: MPS, комментарий: миль/ч)

добавьте это в объявление:

private static long compDate = System.currentTimeMillis();
private static long lastNotifDate = System.currentTimeMillis();

и начало метода запуска:

currX += (System.currentTimeMillis() - compDate) * CONSTANT_SPEED_IN_MPS / 1000;
compDate = System.currentTimeMillis();

if (compDate - lastNotifDate > 1000) {
    lastNotifDate = System.currentTimeMillis();
...

Ответ 4

Возможно, вам не нужен код для запуска в режиме реального времени, но просто имитируйте его и вычислите значения реального времени?

Ответ 5

Хорошо, если это симуляция, тогда вы не будете знать впереди каких-то выбоин. мой лучший выбор - переместить:

                // do something
                try {
                    messageQueue.poll(1000, TimeUnit.MILLISECONDS);

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }'

после или до этого:

            if (incrementor % (1000 / CAR_UPDATE_RATE_IN_MS) == 0) {
            .. code ..
            }

и изменить аргумент в опросе от 1000 до 1 (или 0, если это означает, что опрос не будет ждать, но выйдите из него)

Ответ 6

Как вы говорите,

Проблема, с которой я столкнулся, - это часть "обычно мгновенно". Если я не получу ответ достаточно быстро, я думаю, что он сбросит все время моего алгоритма. Каков наилучший способ справиться с этой ситуацией?

В идеальном мире ваши компьютерные часы идеальны, сбор мусора является атомарным, мгновенным и в O (1), сети не имеют задержек, ОС не имеет прерываний, а Мерфи крепко спит.

Поскольку вы имеете дело с ситуацией в реальном мире, вам нужно приспособиться к типичной для него неопределенности. Во-первых, вам нужна статистика. Конечно, Java GC никогда не гарантируется в режиме реального времени, но вы можете иметь довольно хорошее приближение, которое работает в 90% случаев. Остальные 10% могут быть обработаны другим "планом B", таким образом, и так далее.

Другими словами: запустите свою систему и попытайтесь как можно меньше помешать ей; собирать статистику использования; работайте над лучшими обходными решениями для этих обстоятельств. Например,

  • введите случайные задержки в симуляционном моделировании и посмотрите, как он реагирует ( unit test!); возможно, вы хотите запустить метод run() каждые 500 мс?
  • используйте шаблон наблюдателя (как предложено в другом месте);
  • имеют как можно меньше кода в методе run(); возможно, запустите его каждые 1sec - epsilon, где epsilon - достаточно маленький интервал, который учитывает задержку с наибольшей дисперсией в достаточно большом образце
  • имеют два отдельных потока, выполняемых одновременно, синхронизируя их с помощью блокировки, усредняя время их работы, чтобы получить лучшие часы

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

Ответ 7

Размер зерна пространства обнаружения столкновения кажется мне слишком маленьким, чтобы надежно зависеть от JMS.

Я бы изменил это так, чтобы Mover получил разумный кусок карты, который он может использовать локально, например. если вся карта равна 100 x 100, тогда Mover должен получить не менее 10 x 10 частей сетки.

Эта часть сетки может быть опрошена локально для выбоин при каждом движении, и когда местоположение приближается к границе участка 10 x 10, можно запросить следующий квадрат.

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

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

Удачи.

Ответ 8

Попросите компьютер B отправить местоположение выбоины, когда он обнаружит его, затем компьютер A может переместить автомобиль в это положение. Если автомобиль на компьютере А делает что-то другое, чем просто сидеть там, когда он попал в выбоину, то, возможно, эта статья поможет вам уменьшить внезапное изменение положения/направления/скорости: http://www.gamedev.net/reference/programming/features/cubicsplines/

  • Компьютер A: компьютер, который отправка его позиции
  • Компьютер B: компьютер, который проверяет выбоины.

Ответ 9

Нельзя ли использовать Concurrency или какую-нибудь технику Read-ahead?

Я имею в виду, что ваша проблема ждет сообщения message. Если бы вы могли Асинхронно, не помогло бы? Возможно, использовать обратный вызов?

Вы могли бы сохранить состояние при вызове процесса B и продолжить процесс A. Если Process B отвечает некоторой ошибкой, остановите и верните состояние в сохраненные значения.

Ответ 10

Есть ли у вас большой опыт моделирования дискретных событий? Концепция заключается в том, что вы заранее планируете события в календаре, отслеживаете время, в течение которого эти события происходят в списке, и обновляете состояние системы по прибытии в любое дающее событие с помощью набора правил. Вместо того, чтобы беспокоиться о времени, требуемом для запуска вызываемой подпрограммы, вы эффективно планируете будущее в списке. Имеет ли это смысл? Дайте мне знать, если вам нужна дополнительная информация/ссылки.

Ответ 11

Возможно, для быстрого ответа используется Observer, а не передача сообщений?

Ответ 12

Я бы сказал, что самое большое изменение, которое должно быть сделано, -

Удалите асинхронную связь, то есть JMS, и поставьте некоторый синхронный механизм связи.

Это может быть вызов RPC/WebService Call.

--- Update ---

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

Тогда мы должны будем признать, что мы не можем принять решение, пока сообщение JMS не поступило. Вероятно, в этом сценарии очень мало того, что можно было бы сделать...

Ответ 13

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

Вот некоторые моменты, которые могут помочь вам ускорить доставку JMS, но в JMS-мире можно гарантировать только доставку, а не скорость.

Не могу не упомянуть, что вы также должны рассмотреть решение для кеширования. Я получил хороший answer для этого типа кеша для одного из моих вопросов о SO..... И это потрясает!