跳到主要内容

变量、输入与记忆

Microbe Studio 给你四个存值的地方,它们只在一件事上不同:值活多久、谁看得见。 选错正是"我的计数器被重置了"和"我的两个实例在抢同一个值"的头号成因。

本页把四个都画在地图上。

目的

对任何一条数据,用本页决定:

  • 它该是变量还是记忆条目
  • 它要活过运行吗?活过应用重启吗?别的实例要看见吗?
  • 操作员要在运行前手动输入它吗?

四个家,一览

存活期可见者典型用途
流程变量scope: flow一次运行仅该运行计数器、循环状态、OCR 结果
实例变量scope: global永久,跨重启一个实例上的所有流程"这个实例登录的是哪个账号"
Runtime Memory你选的按条目 TTL取决于记忆作用域(下文)"15 分钟内别再碰这个目标"
Flow Input 参数一次运行,启动时提供该运行"这趟处理多少个"

流程变量

流程变量在流程的 Variables 对话框声明:路径(vars.gem_farmed_trip)、类型、可选默认值。

类型

可声明的类型:

stringnumberbooleanpointrectobjectarraynull

null 外每种类型都有带尾缀 ?可空变体——number?string? 等。可空变量允许持有 null;不可空的不允许,违反声明的值会以 TYPE_MISMATCH 拒绝启动运行。

如何初始化

每次运行开始时,严格按此顺序:

  1. 所有已声明变量置 null
  2. defaultValue 的应用之。
  3. 应用流程的 initialValues
  4. 每个值对照声明类型检查。
  5. 任何值违反声明,运行不启动

这个顺序意味着默认值总胜过 null,初始值总胜过默认值。

读与写

在几乎所有文本框里用两种等价语法引用变量:

{{gem_farmed_trip}}
${gem_farmed_trip}

Variable 节点写变量,它持有一列赋值行。每行有目标和操作:

操作效果
set求值表达式并存结果
clear把变量重置为声明的默认值
delete从上下文移除变量
log把当前值写进运行日志(不改动)

set 行还可带 expire afterttlSeconds,至多一年)。到期后值回到声明默认值,而非消失。

计数器惯用法

产品里最有用的双节点惯用法:

  1. Variable 节点:vars.items_done = {{items_done}} + 1
  2. If 节点:{{items_done}} >= {{max_per_trip}}

这一对给你"做 N 次、N 按次提供",不需要循环节点,而且经得起分支——循环计数器可经不起。

实例变量

在声明上设 scope: global——UI 里标为 Instance——彻底改变存储:

  • 跨运行、跨应用重启持久
  • 该实例上的每个流程共享。
  • 实例之间隔离:A 与 B 各有一份。

用于设备的事实,不是运行的事实。"登录了哪个账号"、"这实例做过首次设置没"、"这实例在哪个服务器"。

实例变量很黏

因为跨重启存活,一个过期的实例变量会在多天后悄悄影响运行。给它们一条刻意的重置路径——设置流程里的一行 clear——别假设每次都是干净开局。

Flow Input 参数

给声明打上 input 标记,它就成为 Flow Input 参数:在流程内仍是普通变量,但会在运行前被拿出来供输入。

  • 操作员在 Dashboard 的 Run Condition 表单填写。
  • 标记 required 则留空时阻止运行。
  • Sub Flow 节点能把父表达式绑定到子输入——真正的传参。

这就是把流程变成可复用函数的东西:

子声明它需要什么;父在调用点提供。子对调用者一无所知,因此同一个子能从队列条目、计划或三个不同的父运行。

Runtime Memory

变量回答"此次运行此刻什么为真"。Runtime Memory 回答另一个问题:"这东西我处理过了吗?多久之前?"

它是带按条目 TTL 的多条目键值仓库,由 Runtime Memory 节点写、Memory Match 节点查。

四种记忆作用域

值得精确记住的部分:

作用域活过运行结束活过应用重启跨实例共享
run
session——一次应用启动否——每实例私有
persist否——每实例私有
shared——唯一跨实例作用域
  • run 活在运行自己的执行上下文上,随运行消失。
  • session 意为"本次应用启动"。新启动从空开始。
  • persist 由 SQLite 支撑,重启安全。
  • shared 是跨实例协调的唯一刻意开关。其余作用域按实例做命名空间,实例 A 永远读不到、盖不掉实例 B 的记忆。
shared 是真共享

十个实例往 shared 写同一个键就会互相覆盖。只在跨实例协调正是目的时用它——例如全局"该目标已被认领"清单。凡按设备的,用 persist

冷却守卫模式

Runtime Memory 的经典用法:别再处理刚处理过的东西。

Memory Match 用可引用受测条目 {{item.<字段>}} 的表达式对每条存活条目比较候选者:

(abs({{current_x}} - {{item.x_coordinate}}) <= 1) && (abs({{current_y}} - {{item.y_coordinate}}) <= 1)

读作"有没有已记住的条目在我现在位置一格之内?"——容差匹配,不是严格相等,这正是真实屏幕数据需要的。

条目带 900 秒 TTL,守卫 15 分钟后自动过期。什么都不用清理。

记忆操作

操作做什么需要 key
remember追加条目(key 空则自动生成)
forget按 key 移除一条
clear清空整个记忆
count把存活条目数写入变量

怎么选:决策表

你想……
在一次运行里数迭代流程变量
运行前传入一个数Flow Input 参数
记住这台模拟器用哪个账号实例变量
15 分钟内避免重访某目标Runtime Memory,persist,TTL
仅本次运行内避免重访Runtime Memory,run
让所有实例共避一张目标单Runtime Memory,shared

最佳实践

  • 声明你用的每个变量。 未声明的引用在启动时失败而不是运行中——那是你想要的失败方式。
  • 计数器默认 0,不是 null null + 1 不是数。
  • OCR 写的一律 number? 失败的读取不产生值,不可空声明会拒绝它。
  • TTL 优于手动清理。 自动过期的条目不会泄漏。
  • 输入按它驱动的决策命名——max_per_trip,不是 n
  • 在自然边界重置行程计数器,不是循环顶部。参考自动化在流程回基地时重置——"一趟"真正结束的点。

性能笔记

  • 变量读取与表达式求值在内存中,几乎免费。别为性能回避变量。
  • persistshared 的操作走 SQLite。快,但是 I/O——别把 remember 放进每秒跑几百次的紧循环。
  • count 扫描存活条目。记忆很大时,自己维护一个计数变量更好。

内存笔记

  • 每个会话携带全套流程变量的独立副本。一个流程跑 10 个实例即 10 套独立变量。
  • run 作用域的 Runtime Memory 挂在执行上下文上,运行终止即释放。
  • session 作用域存于共享数据库、按启动令牌命名空间;应用启动时回收上一次启动的行,不会无限增长。
  • 记忆按绝对时间过期,写入 900 秒 TTL 的条目重启后照样过期——存的是到期时刻,不是内存里的倒计时。

常见错误

错误症状修复
计数器声明无默认值算术啥也不产出默认 0
不可空变量绑 OCR 结果运行被 TYPE_MISMATCH 拒绝声明 number? / string?
shared 存按设备状态实例互相覆盖persist
指望 session 活过重启重启后空persist
循环顶部重置行程计数永远到不了上限在行程边界重置
假设实例变量开局干净好几天前的旧值在设置流程里显式清

故障排查

我的计数器永远是 1。 Variable 节点在重置而不是递增。确认表达式是 {{x}} + 1 而不是 1

运行拒绝启动,报 TYPE_MISMATCH 某个默认或初始值不符合声明类型。最常见:该可空的 OCR 目标被声明成不可空。

Memory Match 从不命中。 查两个节点的作用域——run 作用域的 remember 对读 persist 的 match 不可见。再确认表达式里的字段名与你存的字段一致。

两个实例互相跳过对方的工作。 它们共享着 shared 作用域的记忆。换成 persist 按设备隔离。

FAQ

{{name}}${name} 有区别吗? 没有。都接受、行为一致。选一种保持统一。

子流程能改父流程的变量吗? 子把绑定输入收为自己的局部变量。结果通过子的终止状态传回,或用共享记忆作用域。

变量 TTL 到期后变成什么? 回到声明的默认值——不会变 null,除非默认值就是。

实例变量在机器之间同步吗? 不。它只属于该安装上的那个实例。

相关页面