在 Scala 中评估地图基本上有两种选择。
- 当需要下一个值时,惰性求值计算作为参数传递的函数。如果函数需要一小时才能执行,那么在需要该值时等待一小时。(例如
Stream
和Iterator
) - 急切评估在定义地图时计算函数。它生成一个新列表(
Vector
或其他)并存储结果,使程序在那段时间很忙。 - 我们可以在单独的线程
Future
中获取列表(Seq
或其他),这意味着我们的线程不会阻塞,但必须存储结果。
所以我做了一些不同的事情,请在这里查看。
这是前一段时间,所以我不记得我是否测试过。关键是要有一个映射同时(非阻塞)和急切地应用于一组元素,填充缓冲区(计算机中核心数量的大小,而不是更多)。这意味着:
- 映射的调用不会阻塞当前线程。
- 获取元素不会阻塞当前线程(以防之前有时间计算它并将结果存储在缓冲区中)。
- 可以处理无限列表,因为我们只预取几个结果(大约 8 个,取决于内核的数量)。
所以这一切听起来都很好,你可能想知道问题出在哪里。问题是这个解决方案不是特别优雅的恕我直言。假设我共享的代码在 Java 和/或 Scala 中工作,要遍历 map 生成的可迭代对象中的元素,我只需要编写:
new CFMap(whateverFunction).apply(whateverIterable)
但是我想写的是这样的:
whateverIterable.bmap(whateverFunction)
正如 Scala 中常见的那样('b' 用于缓冲),或者类似:
whateverThing.toBuffered.map(whateverFunction)
它们中的任何一个都对我有用。所以问题是,我怎样才能在 Scala 中以惯用的方式做到这一点?一些选项:
- Monads:创建一个新的集合“缓冲”,这样我就可以使用 toBuffered 方法(应该作为隐式添加到以前的方法中)并实现
map
这个缓冲的东西以及其他所有东西(听起来像是相当多的工作)。 - Implicits:创建一个隐式方法,将通常的集合或它们的超类(我不确定它应该是哪个,
Iterable
也许?)转换为我可以应用该.bmap
方法并从中获取某些东西的其他东西,可能是可迭代的。 - 其他:到目前为止,我可能还没有考虑很多选项。有可能某些库已经实现了这一点(我实际上对相反的情况感到惊讶,我不敢相信以前没有人想到这一点)。使用已经完成的东西通常是一个好主意。
如果有不清楚的地方,请告诉我。