如何让Resource程序无限循环运行?useForever仅执行一次问题求助
问题分析与解决方案
你的代码存在关键逻辑误解:Resource.eval会把IO操作绑定到Resource的资源获取(acquire)阶段执行,而非使用(use)阶段。调用useForever时,Resource会一次性完成所有acquire步骤——也就是执行一次engine.createSth和一次2秒睡眠——随后进入use阶段,但你的use阶段没有持续执行的逻辑,仅维持资源不释放,因此目标操作只会运行一次。
正确实现方式
要实现「初始化资源后无限循环执行操作」的需求,需将一次性初始化逻辑放到Resource的acquire阶段,将循环执行的业务逻辑放到use阶段。以下是两种清晰的实现写法:
写法1:直接组合初始化与循环
val program: Resource[IO, Nothing] = Resource.eval(engine.createSth).flatMap { _ => // 定义无限循环逻辑:执行操作 → 休眠2秒 → 重复 val infiniteLoop: IO[Nothing] = IO(engine.doSth) *> IO.sleep(2.seconds) *> infiniteLoop Resource.eval(infiniteLoop) } program.useForever.as(ExitCode.Success)
写法2:拆分初始化与循环逻辑
// 仅执行一次的资源初始化Resource val initResource: Resource[IO, Unit] = Resource.eval(engine.createSth) // 无限循环执行的业务IO val taskLoop: IO[Nothing] = for { _ <- IO(engine.doSth) // 替换为你需要重复执行的操作 _ <- IO.sleep(2.seconds) _ <- taskLoop } yield () // 组合资源与循环:先初始化,再持续运行循环 val program: Resource[IO, Nothing] = initResource.flatMap(_ => Resource.eval(taskLoop)) program.useForever.as(ExitCode.Success)
关键说明
initResource负责一次性完成资源创建(如engine.createSth),仅在程序启动时执行一次。taskLoop是需要无限重复的业务逻辑,通过递归调用实现循环,每次执行后休眠2秒。useForever会让Resource的use阶段持续运行循环逻辑,不会触发资源释放,从而保持应用持续运行且循环执行目标操作。
内容的提问来源于stack exchange,提问作者LancerX
相关产品推荐
相关产品推荐

