简体   繁体   English

如何在给定异步的情况下使用cats-effect的IO生成Traversable

[英]How to produce a Traversable with cats-effect's IO given an async that will call multiple times

What I'm really trying to do is monitor multiple files and when any of them is modified I'd like to update some state and produce a side effect using this state. 我真正想做的是监视多个文件,当其中任何一个被修改时,我想更新一些状态并使用此状态产生副作用。 I imagine what I want is a scan over a Traversable that produces a Traversable[IO[_]] . 我想象我想要的是对产生一个Traversable[IO[_]]Traversable进行scan But I don't see the path there. 但我看不到那条路。

as a minimal attempt to produce this I wrote 作为产生这种尝试的最小尝试

package example

import better.files.{File, FileMonitor}
import cats.implicits._
import com.monovore.decline._
import cats.effect.IO
import java.nio.file.{Files, Path}
import scala.concurrent.ExecutionContext.Implicits.global

object Hello extends CommandApp(
  name = "cats-effects-playground",
  header = "welcome",
  main = {
    val filesOpts = Opts.options[Path]("input", help = "input files") 
    filesOpts.map { files =>
      IO.async[File] { cb  =>
        val watchers = files.map { path =>
          new FileMonitor(path, recursive = false) {
            override def onModify(file: File, count: Int) = cb(Right(file))
          }
        }
        watchers.toList.foreach(_.start)
      }
        .flatMap(f => IO { println(f) })
        .unsafeRunSync
    }
  }
)

but this has two major flaws. 但这有两个主要缺陷。 One it creates a thread for each file I'm watching, which is a little heavy. 它为我正在观看的每个文件创建一个线程,这有点累。 But more importantly the program finishes as soon as a single file is modified, even though onModify would be called more times if the program stayed running. 但是更重要的是, onModify修改了一个文件,程序就会立即完成,即使如果程序保持运行状态, onModify也会被调用多次。

I'm not married to using better-files, it just seemed like the path of least resistance. 我不喜欢使用更好的文件,这似乎是阻力最小的途径。 But I do require using Cats IO. 但是我确实需要使用Cats IO。

This solution doesn't solve the issue of creating a bunch of threads, and it doesn't strictly produce a Traversable, but it solves the underlying use case. 该解决方案不能解决创建一堆线程的问题,也不能严格产生Traversable,但是可以解决基础用例。 I'm very open to this being critiqued and a better solution provided. 我很乐意接受这种批评,并提供更好的解决方案。

package example

import better.files.{File, FileMonitor}
import cats.implicits._
import com.monovore.decline._
import cats.effect.IO
import java.nio.file.{Files, Path}
import java.util.concurrent.LinkedBlockingQueue
import scala.concurrent.ExecutionContext.Implicits.global

object Hello extends CommandApp(
  name = "cats-effects-playground",
  header = "welcome",
  main = {
    val filesOpts = Opts.options[Path]("input", help = "input files")
    filesOpts.map { files =>
      val bq: LinkedBlockingQueue[IO[File]] = new LinkedBlockingQueue()
      val watchers = files.map { path =>
        new FileMonitor(path, recursive = false) {
          override def onModify(file: File, count: Int) = bq.put(IO(file))
        }
      }
      def ioLoop(): IO[Unit] = bq.take()
          .flatMap(f => IO(println(f)))
          .flatMap(_ => ioLoop())

      watchers.toList.foreach(_.start)
      ioLoop.unsafeRunSync
    }

  }
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM