总是在用List,来了解一波Sequence

云平台

  前言

  最近看到一个概念:Sequence。挺有意思。Google了一篇挺不错的文章,自己翻译了一下,贴出来大家一起“乐呵乐呵”。

  原文地址(自备科学上网):https://medium.com/@elye.project/kotlin-slow-list-and-lazy-sequence-61691fc974c5

  一、List

  在我们开始讲述为什么Sequence更好(在某些情况下)之前,让我告诉你一些关于List的事情。

  先看一段List与Iterator应用的代码:

  val list = listOf(1, 2, 3, 4, 5, 6)list.map{ it * 2 }.filter { it % 3 == 0 }.average()

  兢兢业业,一步步执行,为了更明显一点咱们打一点log。

  val list = listOf(1, 2, 3, 4, 5, 6)val result = list .map{ println("In Map"); it * 2 } .filter { println("In Filter");it % 3 == 0 }println("Before Average")println(result.average())看一下结果:

  每一步都被执行了。似乎这没什么好奇怪的。但是我们来看个有趣的内容:Sequence。

  二、Sequence

  2.1、普通使用

  这里我们可以使用asSequence(),让我们的List转成一个Sequence。上代码:

  val list = listOf(1, 2, 3, 4, 5, 6)val result = list.asSequence() .map{ println("In Map"); it * 2 } .filter { println("In Filter");it % 3 == 0 }println("Before Average")println(result.average())看一下log结果:

  Before Acerage被先打出来了。这就有意思了……换句话说,如果我们不调用average(),则不会对Sequence执行任何操作。

  没错,它是懒惰的,只要不主动调用消费操作,Sequence就不会进行任何调用。(这一点有点类似于懒加载)

  这时可能有小伙伴拎着40米的长刀:我tm就是要执行遍历,你给我来个懒加载是几个意思?

  兄dei,刀放下,不要着急听我继续给你“吹”,不不不…继续给你唠。

  我们不要只盯着懒加载,不知道有没有注意到它在In Map和In Filter中交错执行。 这意味着,它并非是先遍历执行完第一个集合然后再遍历执行完第二个集合。而是把多个遍历操作,打成一条链,遍历这个链…可能不好理解,咱们上个图:

  2.2、Sequence优势

  我猜大家依然n脸蒙蔽…咱们稍稍改改demo,第一个demo咱们先用List做对比:

  val list = listOf(1, 2, 3, 4, 5, 6)val result = list .map{ println("In Map $it"); it * 2 } .filter { println("In Filter $it");it % 3 == 0 }println(result.first())调用first()方法。看一下log:

  很正常。接下来咱们看一下“不正常”的Sequence:

  val sequence = sequenceOf(1, 2, 3, 4, 5, 6)val result = sequence .map{ println("In Map $it"); it * 2 } .filter { println("In Filter $it");it % 3 == 0 }println(result.first())

  2.3、map对比

  是不是看出Sequence的有趣之处了?其实Sequence的优化点在于map上,咱们继续进行一组测试:

  val sequence = generateSequence(1) { it + 1 }.take(50000000)val list = sequence.toList()println("List Map Sum= " + measureNanoTime { list.map { it * 2 }.sum() })println("Sequence Map Sum " + measureNanoTime { sequence.map { it * 2 }.sum() })println("List Map Average " + measureNanoTime { list.map { it * 2 }.average() })println("Sequence Map Average " + measureNanoTime { sequence.map { it * 2 }.average() })

  可以看出,在map下,Sequence要比List快4-7倍。但是,是不是Sequence就一定比List强呢?让我们换个操作符看一下:

  2.4、filter对比

  val sequence = generateSequence(1) { it + 1 }.take(50000000)val list = sequence.toList()println("List Filter Sum " + measureNanoTime { list.filter { it % 3 == 0 }.sum() })println("Sequence Filter Sum " + measureNanoTime { sequence.filter { it % 3 == 0 }.sum() })println("List Filter Average " + measureNanoTime { list.filter { it % 3 == 0 }.average() })println("Sequence Filter Average " + measureNanoTime { sequence.filter { it % 3 == 0 }.average() })

  可以看出来,在filter中,List的表现要高于Sequence。

  总结

  如果不需要额外操作符,使用List如果只有Map操作符,使用Sequence如果只有Filter操作符,使用List如果需要类似first()的操作符,可以酌情考虑使用Sequence。

标签: 云平台