Разработка этого алгоритма лучший путь?

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

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

  1. У меня есть механизм, перемещающийся в направление X на скорости (24,5872 члена парламента)
  2. Я моделирую, это путем постепенного увеличения этих X оценивает каждые 100 мс с помощью исполнителя (Для хранения его X положений более точными и оперативными)
  3. После каждой секунды я отправляю сообщение в другой процесс с xMin и xMax значениями строки, которую я просто покрыл
  4. Другой процесс ответит сообщением JMS (обычно немедленно) сообщение мне остановиться, если была "Выбоина" в предыдущем X областей (передайте сообщение об обратном вызове к linkedblockingqueue).

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

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

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

    }

}
10
задан mainstringargs 3 March 2010 в 19:23
поделиться

13 ответов

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

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


1a. Начните с отправки текущего местоположения транспортного средства.

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

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

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

.

Наблюдатель за движением транспортных средств


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

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

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

.

Транспортное движение


3a. Зарегистрируйте наблюдателя шага 2а для наблюдения за перемещениями транспортного средства

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              |
+---------------------------------------------+
6
ответ дан 3 December 2019 в 22:36
поделиться

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

{{ 1}}
1
ответ дан 3 December 2019 в 22:36
поделиться

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

  • Компьютер A: компьютер, который отправляет информацию о своем местоположении
  • Компьютер B: компьютер, который проверяет выбоины
0
ответ дан 3 December 2019 в 22:36
поделиться

Разве нельзя было бы использовать Параллелизм или какой-нибудь метод упреждающего чтения ?

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

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

0
ответ дан 3 December 2019 в 22:36
поделиться

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

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

3
ответ дан 3 December 2019 в 22:36
поделиться

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

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

edit: - будьте осторожны с единицами измерения (имя константы: MPS, комментарий: mph)

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

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();
...
2
ответ дан 3 December 2019 в 22:36
поделиться

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

                // 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, если это означает, что опрос не будет ждать, а немедленно прекратится)

1
ответ дан 3 December 2019 в 22:36
поделиться

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

0
ответ дан 3 December 2019 в 22:36
поделиться

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

0
ответ дан 3 December 2019 в 22:36
поделиться

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

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

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

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

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

Удачи.

1
ответ дан 3 December 2019 в 22:36
поделиться

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

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

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

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

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

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

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

1
ответ дан 3 December 2019 в 22:36
поделиться

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

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

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

--- Обновление ---

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

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

0
ответ дан 3 December 2019 в 22:36
поделиться

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

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

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

0
ответ дан 3 December 2019 в 22:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: