Я работаю намного более сложная версия этого (с механизмом, перемещающимся в оба направления X и Y)
Я сделал этот пример для получения идей о лучших способах выполнить это.
Проблема, которую я имею, с "обычно немедленно" частью. Если я не получаю достаточно быстрый ответ, я думаю, что он отбросит целую синхронизацию моего алгоритма. Что лучший путь состоит в том, чтобы обработать эту ситуацию?
Вот некоторый абсолютный код того, что я пытаюсь сделать:
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
}
}
Я предлагаю изменить ваш алгоритм выше, как показано в шагах ниже.
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 |
+---------------------------------------------+
Может быть, вам не нужен код для работы в реальном времени, а просто моделируйте его и вычисляйте значения в реальном времени?
{{ 1}}Попросите компьютер B отправить обратно местоположение выбоины, когда он обнаружит ее, тогда компьютер A сможет переместить транспортное средство в это положение. Если автомобиль на компьютере A делает что-то, кроме того, что просто сидит там, когда он врезался в выбоину, возможно, эта статья поможет вам уменьшить внезапное изменение положения / направления / скорости: http: // www .gamedev.net / reference / programming / features / cubicsplines /
Разве нельзя было бы использовать Параллелизм или какой-нибудь метод упреждающего чтения ?
Я имею в виду, что ваша проблема ждет сообщения messageQueue. Если бы вы могли использовать Async, разве это не помогло бы? Возможно, использовать обратный вызов?
Возможно, вы могли бы сохранить состояние при вызове процесса B и продолжить процесс A. Если процесс B отвечает с некоторой ошибкой, остановитесь и верните состояние к сохраненным значениям.
Если вы не запускаете систему в сетях и операционных системах, которые предоставляют гарантии в реальном времени, иногда будут задержки. Итак, вы должны уметь обнаруживать эти задержки и решать, как реагировать - останавливается ли время для вашей стороны симуляции, пока машина не узнает, как карта разворачивается под ней? или время продолжает течь, но выбоина, о которой было сообщено позже, появляется дальше по дороге, чем могла бы? или поздно появившаяся выбоина обнаружена как запоздавшая и проигнорирована?
Я не слишком знаком с текущим состоянием обмена сообщениями Java. Вы можете уточнить, блокирует ли messageQueue.poll
? Если вы отправляете сообщение, а затем блокируете ответ, возникает вопрос, почему вы не используете что-то синхронное, например, вызов метода удаленного объекта, поскольку это определенно поможет инфраструктуре получать сообщения без промедления.
Я бы сохранил время вычисления 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();
...
ну, если это симуляция, то вы не будете знать заранее, какие выбоины. пока что лучше всего двигаться:
// 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, если это означает, что опрос не будет ждать, а немедленно прекратится)
Есть ли у вас большой опыт в дискретно-событийном моделировании? Концепция заключается в том, что вы заранее планируете события в календаре, отслеживаете время наступления этих событий в списке и обновляете состояние системы при наступлении любого события с помощью набора правил. Вместо того чтобы беспокоиться о времени, необходимом для выполнения вызванной подпрограммы, вы эффективно планируете будущее в списке. Есть ли в этом смысл? Дайте мне знать, если вам нужна дополнительная информация / ссылки.
Возможно ли использовать Observer вместо передачи сообщений для быстрого ответа?
Размер зерна пространства обнаружения столкновений кажется мне слишком маленьким, чтобы надежно зависеть от JMS.
Я бы изменил это так, чтобы Mover получал разумный фрагмент карты, который он мог бы использовать локально, например если вся карта имеет размер 100 x 100, то Mover должен получить как минимум часть сетки размером 10 x 10.
Эта часть сетки может опрашиваться локально на наличие выбоин при каждом движении, и когда местоположение приближается к границе участка 10 x 10, тогда может быть запрошен следующий квадрат.
Это даст вам своего рода окно с двойным буфером, где можно загрузить новую клетку, в то время как оставшиеся ходы будут продолжать оцениваться по старому квадрату.
Кроме того, вы можете иметь возможность отслеживать изменения в квадратах, чтобы, когда кто-то добавляет новую выбоину в квадрат, который был ранее загружен, этот новый квадрат будет транслироваться, и все клиенты, у которых есть этот квадрат загруженный в данный момент может перезагрузить его.
Удачи.
Как вы говорите,
У меня проблема с частью «обычно мгновенно». Если я не получу ответ достаточно быстро, я думаю, это нарушит весь мой алгоритм. Как лучше справиться с этой ситуацией?
В идеальном мире часы вашего компьютера идеальны, сборка мусора выполняется атомарно, мгновенно и в O (1), в сетях нет задержки, в ОС нет прерываний, а Мерфи крепко спит .
Поскольку вы имеете дело с реальной ситуацией, вам необходимо учитывать типичную для нее неопределенность. Во-первых, вам нужна статистика . Конечно, Java GC никогда не гарантирует работу в реальном времени, но у вас может быть довольно хорошее приближение, которое работает в 90% случаев. Остальные 10% могут быть обработаны другим «планом Б» и т. Д.
Другими словами: запустите свою систему и постарайтесь помешать ей, насколько это возможно; собирать статистику использования; работайте над лучшими обходными путями для этих обстоятельств. Например,
1сек - эпсилон
, где эпсилон - достаточно маленький интервал, который учитывает задержку с наибольшей дисперсией в достаточно большой выборке В крайнем случае, нет точного решения, поскольку нет точного «реального» мира.Добавьте шума, приготовьтесь к худшему, усредните остальное.
Я бы сказал, что самое большое изменение, которое следует сделать, это -
Убрать асинхронную связь, то есть JMS, и установить какой-нибудь механизм синхронной связи.
Это может быть вызов RPC / вызов WebService.
--- Обновление ---
Только что видел ваш комментарий о том, что вы не можете удалить часть JMS, которая является частью гораздо большей системы.
Тогда нам придется признать, что мы не можем принять решение, пока не пришло сообщение JMS. Вероятно, в этом сценарии сделать очень мало ...
Достижение почти мгновенной доставки сообщений с помощью JMS здесь будет сложной задачей. По сути, JMS была разработана с упором на гарантию доставки, а не на ее скорость.
Здесь приведены некоторые моменты, которые могут помочь вам ускорить доставку JMS, но в мире JMS можно гарантировать только доставку, а не скорость.
Я не могу не упомянуть, что вам также следует подумать о решении для кеширования. Я получил хороший ответ для этого типа кеша на один из моих вопросов по SO. .... И это круто!