我正在研究一个更为复杂的版本(车辆在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
}
}
答案 0 :(得分:6)
我建议对上面的算法进行更改,如下面的步骤所示。
JMS调用其他进程
1a上。首先发送车辆的当前位置。
1b中。另一个过程将使用JMS消息进行响应,该消息包含车辆位置可见区域中所有“Pot hole位置”的列表。在客户端保留此“可见的坑洞位置”列表,以便在下面的步骤中使用。
1c上。我们将可见区域定义为车辆的邻近区域,即使使用JMS调用其他过程的(1秒延迟+网络滞后),车辆的移动也不应越过该区域。
1D。每隔一秒后,重复步骤1a和1b,并在客户端替换相对于车辆当前位置的坑洞位置列表。
车辆运动观察员
2a上。实施观察员模式,可以接收车辆运动的通知。
2B。每次生成事件时,观察者都会检查车辆的位置是否与步骤1b中获得的可见坑洞列表中的一个条目匹配。
2c中。如果找到匹配,宾果游戏!你必须停止车辆。
车辆运动
3A。注册步骤2a观察员观察车辆的运动
3B。等到你从步骤1b得到至少第一个可见的坑洞清单。
3c上。通过每100毫秒递增X值开始移动车辆。每次移动时,都应通知步骤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 :(得分:3)
除非您在提供实时保证的网络和操作系统上运行系统,否则 偶尔会出现延迟。因此,您必须能够检测到这些延迟并决定如何响应 - 在汽车发现地图如何展开之前,时间是否停留在模拟的一侧?或者时间是否继续流动但是迟到的通知坑洞在路上比其可能的更远?或者是迟到的坑洞被发现为迟到而被忽略了?
我不太熟悉Java消息传递的当前状态。你能否澄清messageQueue.poll
是否阻止?如果您正在发送消息然后阻止答案,则会引发一个问题:为什么您不使用同步方法,例如对远程对象的方法调用,因为这肯定会帮助基础架构毫不拖延地向您发送消息。
答案 2 :(得分:2)
我会节省currX计算的时间和位置(currX)
下次计算currX时,你会看到自上次以来经过了多少毫秒(System.currMillisec() - lastCalc),将其乘以速度并将其添加到currX。然后将最后的计算日期设置为现在。
编辑: - 小心你的单位(常数名称:MPS,评论:mph)
将其添加到声明:
private static long compDate = System.currentTimeMillis();
private static long lastNotifDate = System.currentTimeMillis();
和run方法的开始:
currX += (System.currentTimeMillis() - compDate) * CONSTANT_SPEED_IN_MPS / 1000;
compDate = System.currentTimeMillis();
if (compDate - lastNotifDate > 1000) {
lastNotifDate = System.currentTimeMillis();
...
答案 3 :(得分:1)
也许您不需要代码实时运行,只是模拟它并计算实时值?
答案 4 :(得分:1)
// 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(如果这意味着民意调查不会等待,则暂时退出)
答案 5 :(得分:1)
正如你所说,
我遇到的问题是“通常是即时”部分。如果我没有足够快地得到响应,我认为它会摒弃我的算法的整个时间。处理这种情况的更好方法是什么?
在一个理想的世界中,你的计算机时钟是完美的,垃圾收集是原子的,瞬时的,在O(1)中,网络没有延迟,操作系统没有中断,墨菲睡着了。
由于您正在处理现实世界的情况,因此您需要针对其典型的不确定性进行调整。首先,您需要统计信息。当然,Java GC永远不能保证是实时的,但你可以有90%的时间使用相当好的近似值。剩余的10%可以由另一个'计划B'处理,依此类推。
换句话说:运行你的系统并试图尽可能地阻止它;收集使用统计;为这些情况制定最佳解决方案。例如,
1sec - epsilon
运行一次,其中 epsilon 是一个足够小的区间,可以解释足够大的样本中具有最高方差的延迟在紧要关头,没有确切的解决方案,因为没有确切的“真实”世界。添加噪音,为更糟糕的情况做好准备,平衡其余部分。
答案 6 :(得分:1)
碰撞检测空间的粒度在我看来太小而不能可靠地依赖于JMS。
我会改变这一点,以便 Mover 收到一个合理的地图块,它可以在本地使用,例如如果整个地图是100 x 100,那么 Mover 应至少接收10 x 10的网格部分。
网格的这一部分可以在每次移动时被局部查询以获得坑洼,并且当该位置接近10×10部分的边界时,则可以请求下一个方格。
这将为您提供一种双缓冲窗口,可以加载新的方块,同时继续对旧方块评估剩余的移动。
此外,您可能希望能够侦听对方块的更改,以便当有人向先前已加载的方块添加新的坑洞时,将广播该新方块以及具有该方块的任何客户端当前加载可以重新加载它。
祝你好运。
答案 7 :(得分:0)
让计算机B在检测到坑洞时发回坑洞的位置,然后计算机A可以将车辆移动到该位置。如果计算机A上的车辆做了其他事情,而不仅仅是在撞到坑洞时坐在那里,那么这篇文章可能会帮助你减少位置/方向/速度的突然变化: http://www.gamedev.net/reference/programming/features/cubicsplines/
答案 8 :(得分:0)
是不是可以使用并发或某些预读技术?
我的意思是你的问题正在等待messageQueue。如果你可以异步它,它不会有帮助吗?也许使用回调?
您可以在调用进程B并继续进程A时保存状态。如果进程B回复了一些错误,则停止并将状态恢复为已保存的值。
答案 9 :(得分:0)
您对离散事件模拟有多少经验吗?这个概念是您在日历上预先安排事件,跟踪这些事件在列表中发生的时间,并在到达具有一组规则的任何给定事件时更新系统的状态。您可以有效地在列表中安排未来,而不必担心运行被调用子例程所需的时间。这有意义吗?如果您需要更多信息/参考,请告诉我。
答案 10 :(得分:0)
可能使用Observer而不是消息传递来快速响应?
答案 11 :(得分:0)
我想说应该做的最大改变是 -
删除异步通信即JMS并放置一些同步通信机制。
这可能是RPC调用/ WebService调用。
<强> --- ---更新强>
刚刚看到你的评论,你无法删除作为更大系统的一方的JMS部分。
然后我们必须接受在JMS消息未到达之前我们无法做出决定。可能在这种情况下可以做的很少......
答案 12 :(得分:0)