From cc850bf7998daa0d785facaca59f89ec2aab6225 Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Mon, 21 Sep 2026 23:53:40 +0800 Subject: perf(sim): M6a 谣言窗口扫描去中间表——最新在前早停递归替代 takeWhile/filter/sort,零分配且等价 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/LivingVillage.Kernel/Sim.fs | 44 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/LivingVillage.Kernel/Sim.fs b/src/LivingVillage.Kernel/Sim.fs index fd50fed..cedadfa 100644 --- a/src/LivingVillage.Kernel/Sim.fs +++ b/src/LivingVillage.Kernel/Sim.fs @@ -685,17 +685,18 @@ module Sim = trimRumors nowTick (rumor :: rumors) let private latestRumorFor (receiver: NpcId) (world: World) : RumorEvent option = - // 工作集最新在前且 Tick 非递增,故只需扫描新鲜窗口;窗口外条目本就会被过滤掉。 - world.Rumors - |> List.takeWhile (fun rumor -> world.Tick - rumor.Tick <= rumorFreshnessTicks) - |> List.filter (fun rumor -> - rumor.Receiver = receiver - && rumor.Tick <= world.Tick - && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength) - |> List.sortByDescending (fun rumor -> - let (RumorId id) = rumor.Id - rumor.Tick, id) - |> List.tryHead + // 工作集最新在前且 Tick 非递增:第一条命中的即“Tick 最大、Id 最大”,与原实现 + // (filter 后 sortByDescending 取头)等价;窗口外无分配提前返回。 + let rec loop (rest: RumorEvent list) : RumorEvent option = + match rest with + | [] -> None + | rumor :: tail -> + if world.Tick - rumor.Tick > rumorFreshnessTicks then None + elif rumor.Receiver = receiver + && rumor.Tick <= world.Tick + && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength then Some rumor + else loop tail + loop world.Rumors /// 工作集最新在前,头节点恒为最大 Id(每次追加 `max+1`),故 O(1) 取下一个 Id。 /// 裁剪只丢尾部旧条目,不会丢头,因此该不变量在裁剪后仍成立。 @@ -826,14 +827,19 @@ module Sim = let private rumorIsDuplicate (request: ChatRequest) (parent: RumorEvent option) (world: World) : bool = let parentId = parent |> Option.map (fun rumor -> rumor.Id) - world.Rumors - |> List.takeWhile (fun rumor -> world.Tick - rumor.Tick <= rumorFreshnessTicks) - |> List.exists (fun rumor -> - rumor.Narrator = request.Narrator - && rumor.Receiver = request.Receiver - && rumor.Parent = parentId - && rumor.Tick <= world.Tick - && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength) + // 窗口外条目强度必 < rumorMinimumStrength,与原全表 exists 等价;命中或越窗即无分配返回。 + let rec loop (rest: RumorEvent list) : bool = + match rest with + | [] -> false + | rumor :: tail -> + if world.Tick - rumor.Tick > rumorFreshnessTicks then false + elif rumor.Narrator = request.Narrator + && rumor.Receiver = request.Receiver + && rumor.Parent = parentId + && rumor.Tick <= world.Tick + && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength then true + else loop tail + loop world.Rumors type private ChatParticipant = | AvatarParticipant -- cgit v1.2.3