F#中如何让绑定的Async异步进程每次调用都重新执行
问题本质原因
F# 中的无显式参数的 let 绑定属于值绑定,而非可重复执行的函数绑定:
- 绑定表达式会在代码首次加载/执行到该绑定行时立刻完成计算,将计算结果固化为和符号关联的固定值
- 后续所有对该符号的引用,都会直接返回这个固化的结果,不会重新执行绑定行里的计算逻辑
对应到你的代码里,执行到 let getAllPatientNames = Async.RunSynchronously (FsNetwork.GetAllPatientNamesAsync()) 这行时,程序就立刻把整个异步逻辑跑完,把首次从数据库拿到的患者名字列表存成了固定值,之后不管多少次引用 getAllPatientNames,拿到的都是第一次存好的旧值,根本不会重新触发数据库查询。
修改方法
要实现“每次调用都重新执行异步获取逻辑”的效果,只需要把原来的值绑定改成带单元(unit)参数的函数绑定即可:
// 错误写法:值绑定,仅在绑定时执行一次 let getAllPatientNames = Async.RunSynchronously (FsNetwork.GetAllPatientNamesAsync()) // 正确写法:带unit参数的函数,每次调用才会执行函数体逻辑 let getAllPatientNames() = Async.RunSynchronously (FsNetwork.GetAllPatientNamesAsync())
调用时只要补上括号,就能触发一次全新的异步执行流程:
// 每次执行这行代码,都会重新走一遍异步拉取数据的逻辑,拿到最新值 { m with names = getAllPatientNames() }
注意事项
- F# 里无参数函数不能省略 unit 参数,如果去掉括号直接写
let getAllPatientNames = Async.RunSynchronously(...),依然是值绑定的逻辑,永远不会重新执行 - 不要误用
lazy绑定解决这个问题,lazy仅会在首次访问时触发计算,后续访问依然返回缓存结果,无法满足动态拉取最新数据的需求 - 从性能角度,尽量避免高频调用时使用
Async.RunSynchronously阻塞线程,可以顺着异步计算的链路从最上游把异步操作串起来,减少线程阻塞的开销
内容的提问来源于stack exchange,提问作者Alan Wayne
相关产品推荐
相关产品推荐

