Anylogic仿真:如何移除流程图中所有Agent?代码报错求助
处理AnyLogic中批量移除流程块内Agent的报错问题
我需要在必要时移除流程图所有块中的剩余Agent,但AnyLogic没有自带的相关方法。自己写了遍历所有块逐个移除Agent的函数,但因为涉及Service、Queue、ConveyorPath、Batch、Wait等多种块类型,方案不仅无效还频繁报错。
原实现代码
for (ConveyorPath conveyor : ersterTeilConveyor) { List list = conveyor.getAgents(); for (Object a : list) { Kerze k = (Kerze) a; traceln(k.currentBlock().getName() + " " + k.getIndex()); conveyor.removeAgent(k); enter4.take(k); } } for (Agent block : ersterTeilBlock) { if (block instanceof Queue) { Queue queue = (Queue) block; int size = queue.size(); for (int i = 0; i < size; i++) { queue.removeFirst(); } } else if (block instanceof Batch) { Batch batch = (Batch) block; for (Agent k : batch.contents()) { traceln(k.currentBlock().getName() + " " + k.getIndex()); batch.remove(k); enter4.take(k); } } else if (block instanceof Delay) { Delay delay = (Delay) block; if (delay.size() > 0) { Kerze k = (Kerze) delay.get(0); traceln(k.currentBlock().getName() + " " + k.getIndex()); delay.remove(k); enter4.take(k); } } } for (ConveyorPath conveyor : zweiterTeilConveyor) { List list = conveyor.getAgents(); for (Object a : list) { Kerze k = (Kerze) a; traceln(k.currentBlock().getName() + " " + k.getIndex()); conveyor.removeAgent(k); enter4.take(k); } } for (Agent block : zweiterTeilBlock) { if (block instanceof Queue) { Queue queue = (Queue) block; for (Agent k : queue.contents()) { traceln(k.currentBlock().getName() + " " + k.getIndex()); queue.remove(k); enter4.take(k); } } else if (block instanceof Batch) { Batch batch = (Batch) block; for (Agent k : batch.contents()) { traceln(k.currentBlock().getName() + " " + k.getIndex()); batch.remove(k); enter4.take(k); } } else if (block instanceof Service) { Service service = (Service) block; int size = service.queueSize(); if (size > 0) { for (int i = 0; i < size; i++) { Kerze k = (Kerze) service.queueGet(i); traceln(k.currentBlock().getName() + " " + k.getIndex()); service.queueRemove(k); enter4.take(k); } } if (service.delaySize() > 0) { Kerze k2 = (Kerze) service.delayGet(0); traceln(k2.currentBlock().getName() + " " + k2.getIndex()); service.delayRemove(k2); enter4.take(k2); } } else if (block instanceof Wait) { Wait wait = (Wait) block; for (Agent k : wait.contents()) { traceln(k.currentBlock().getName() + " " + k.getIndex()); wait.remove(k); enter4.take(k); } } }
报错信息
Exception during discrete event execution: root.enter4.output.output: Internal error: agent 34291 is already pending as 'ready' on some other port: root.enter4.output.output.out java.lang.RuntimeException: root.enter4.output.output: Internal error: agent 34291 is already pending as 'ready' on some other port: root.enter4.output.output.out at com.anylogic.engine.Engine.error(Unknown Source) at com.anylogic.engine.Agent.error(Unknown Source) at com.anylogic.engine.Utilities.error(Unknown Source) at com.anylogic.engine.Utilities.error(Unknown Source) at com.anylogic.libraries.processmodeling.ExtEntityImpl.c(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBlock.notifyReady(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBuffer.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBuffer.take(Unknown Source) at com.anylogic.libraries.processmodeling.Enter.take(Unknown Source) at prozess.Main.removeKerzen2(Main.java:7449) at prozess.Main._sink2_onEnter_xjal(Main.java:6164) at prozess.Main$14.onEnter(Main.java:1895) at prozess.Main$14.onEnter(Main.java:1) at com.anylogic.libraries.processmodeling.Sink.b(Unknown Source) at com.anylogic.libraries.processmodeling.Sink$1.onEnter(Unknown Source) at com.anylogic.libraries.processmodeling.InputBlock$1.b(Unknown Source) at com.anylogic.libraries.processmodeling.InPort.a(Unknown Source) at com.anylogic.libraries.processmodeling.InPort.receiveImmediately(Unknown Source) at com.anylogic.libraries.processmodeling.InputBlock$1.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutPort.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutPort.b(Unknown Source) at com.anylogic.libraries.processmodeling.PlainTransfer$1.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutPort.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutPort.b(Unknown Source) at com.anylogic.libraries.processmodeling.OutPort.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBlock.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBlock$2.a(Unknown Source) at com.anylogic.libraries.processmodeling.OutputBlock$2.action(Unknown Source) at com.anylogic.libraries.processmodeling.AsynchronousExecutor_xjal$a.execute(Unknown Source) at com.anylogic.engine.LibraryEventHandler$i.execute(Unknown Source) at com.anylogic.engine.Engine.f(Unknown Source) at com.anylogic.engine.Engine.fn(Unknown Source) at com.anylogic.engine.Engine$i.run(Unknown Source)
问题分析
报错核心原因是同一个Agent被重复调用enter4.take(k),触发场景包括:
- 部分Agent被误判存在于多个块集合中(比如ConveyorPath和其他块的集合重复包含了同一Agent所在的块)
Batch、Wait块使用contents()遍历的方式有误:遍历原集合时直接修改集合(移除Agent)会导致遍历异常,且部分块的contents()返回的是视图而非实际可修改集合- 移除Agent后调用
take()时,Agent可能还处于原有块的端口调度队列中,导致端口冲突报错
修正方案
核心优化思路
- 用全局Agent集合去重,确保每个Agent只被处理一次
- 针对不同块类型使用正确的移除API,避免遍历修改原集合的问题
- 移除Agent时先清理原有块的关联,再处理后续的
take()操作
修正后的代码
// 先收集所有需要移除的Kerze,用HashSet自动去重 Set<Kerze> kerzenToRemove = new HashSet<>(); // 收集ConveyorPath中的Agent for (ConveyorPath conveyor : ersterTeilConveyor) { for (Object a : conveyor.getAgents()) { kerzenToRemove.add((Kerze) a); } } for (ConveyorPath conveyor : zweiterTeilConveyor) { for (Object a : conveyor.getAgents()) { kerzenToRemove.add((Kerze) a); } } // 收集各类块中的Agent for (Agent block : ersterTeilBlock) { if (block instanceof Queue) { Queue queue = (Queue) block; for (Agent k : queue.contents()) { kerzenToRemove.add((Kerze) k); } } else if (block instanceof Batch) { Batch batch = (Batch) block; for (Agent k : batch.contents()) { kerzenToRemove.add((Kerze) k); } } else if (block instanceof Delay) { Delay delay = (Delay) block; for (int i = 0; i < delay.size(); i++) { kerzenToRemove.add((Kerze) delay.get(i)); } } } for (Agent block : zweiterTeilBlock) { if (block instanceof Queue) { Queue queue = (Queue) block; for (Agent k : queue.contents()) { kerzenToRemove.add((Kerze) k); } } else if (block instanceof Batch) { Batch batch = (Batch) block; for (Agent k : batch.contents()) { kerzenToRemove.add((Kerze) k); } } else if (block instanceof Service) { Service service = (Service) block; // 收集队列中的Agent for (int i = 0; i < service.queueSize(); i++) { kerzenToRemove.add((Kerze) service.queueGet(i)); } // 收集正在服务的Agent for (int i = 0; i < service.delaySize(); i++) { kerzenToRemove.add((Kerze) service.delayGet(i)); } } else if (block instanceof Wait) { Wait wait = (Wait) block; for (Agent k : wait.contents()) { kerzenToRemove.add((Kerze) k); } } } // 逐个处理去重后的Agent for (Kerze k : kerzenToRemove) { traceln(k.currentBlock().getName() + " " + k.getIndex()); // 先从当前所在块精准移除 ProcessBlock currentBlock = (ProcessBlock) k.currentBlock(); if (currentBlock instanceof ConveyorPath) { ((ConveyorPath) currentBlock).removeAgent(k); } else if (currentBlock instanceof Queue) { ((Queue) currentBlock).remove(k); } else if (currentBlock instanceof Batch) { ((Batch) currentBlock).remove(k); } else if (currentBlock instanceof Delay) { ((Delay) currentBlock).remove(k); } else if (currentBlock instanceof Service) { Service service = (Service) currentBlock; if (service.queueContains(k)) { service.queueRemove(k); } if (service.delayContains(k)) { service.delayRemove(k); } } else if (currentBlock instanceof Wait) { ((Wait) currentBlock).remove(k); } // 最后执行take操作,避免端口冲突 enter4.take(k); }
关键说明
- 使用
HashSet收集Agent自动去重,彻底避免重复处理同一个Agent - 先收集所有目标Agent再统一处理,避免遍历块集合时修改集合导致的异常
- 通过
k.currentBlock()获取Agent实际所在的块,精准调用对应移除API,避免误操作 - 移除Agent时先清理其与原块的关联,再执行
take(),解决端口冲突问题
内容的提问来源于stack exchange,提问作者Ephemere
相关产品推荐
相关产品推荐

