如何使用Scala将Iterable[t]
转换为Future[Seq[T]]
?
基本上,我想读取Apache Ignite上的查询返回的所有值,该查询返回一个IgniteCursor。
我想以一种非阻塞的方式从该游标中读取内容。
我可以写:
val iterable = cursor.asScala
val result = iterable.toList
Future{
result
}
但是我认为这段代码是阻塞的,不是异步的。我是对的吗?
将Iterable
转换为Future[Seq]
有意义吗?
我的目标是在不阻止调用者线程或工作线程的情况下获得一小部分记录,因为我将收到许多并发调用。
我的Iterable
实际上是一个IgniteCursor
,因此在内部,我想它会执行一些网络/数据库操作。
通常,有一些方法可以异步执行这些操作。
例如,要读取单个值,我可以使用getAsync
代替get
。
对于游标,我只具有getAll
函数,所以我的想法是以一种聪明的方式使用Iterable
。
我的理解是,使用异步方法时,线程不会被阻塞,但是可以自由执行其他任务,直到网络操作完成为止。
我希望有一个返回Future
/ IgniteFuture
或回调的函数。
有没有一种方法可以在不保持线程阻塞的情况下获取所有记录?
最后,要正确释放资源,我需要调用close
函数。如果我写Future(cursor.asScala.toList)
,何时应该调用close方法?在onComplete
的{{1}}上?
另一种简单的解决方案是编写Future
,但我想内部会阻塞一个工作线程以等待所有记录。
也许我错过了什么?
换句话说,有一种方法可以使用“异步非阻塞IO”从Ignite提取记录列表吗?
答案 0 :(得分:2)
将
Iterable
转换为Future[Seq]
有意义吗?
这取决于您的目标。
Iterable
既懒惰又有效存储。 Seq
渴望并且会占用更多内存。从Iterable
到Seq
,实际上是在说:“在一切准备就绪并加载到内存之前,我不希望看到任何数据。”
通过将其设置为Future[Seq]
,您实际上是在说:“(希望)所有数据元素都准备好并加载到内存后,我稍后会回来。”
答案 1 :(得分:1)
我不明白。如果您只有getAll
,那么您如何才能做到这一点呢?您有两种选择:要么内联调用它,要么卸载到线程。
您可以做的一件事是将呼叫包装到blocking
中:
Future {
blocking {
cursor.getAll.asScala
}
}
这告诉执行者,工作线程将阻塞,因此不会将其计入线程池限制。 单独阻止也不错。只有当它导致线程饥饿时,这才是坏的。
但是要小心。如果您的游标“繁重”,并且您有很多并行运行,那么除了阻塞线程之外,您还会遇到其他问题。 例如,您可能会用完内存,因为您将尝试一次使所有结果都适合那里。否则您将使IO饱和。