To działa, jeśli przekształcenie Range
w List
:
def ttest() = {
val threads =
for (i <- 1 to 5 toList)
yield new Thread() {
override def run() {
println("going to sleep")
Thread.sleep(1000)
println("awake now")
}
}
threads.foreach(t => t.start())
threads.foreach(t => t.join())
println("all done")
}
Problem polega na tym, że "1 to 5
" to Range
i zakresy nie są "surowe", że tak powiem. W języku angielskim, po wywołaniu metody map
na Range
, nie oblicza ona każdej wartości w prawo. Zamiast tego tworzy obiekt - RandomAccessSeq.Projection na Scala 2.7 - który ma odniesienie do funkcji przekazanej do mapy, a innej do pierwotnego zakresu. Tak więc, gdy użyjesz elementu wynikowego zakresu, funkcja, którą przekazałeś do odwzorowania, zostanie zastosowana do odpowiedniego elementu oryginalnego zakresu. I to się stanie za każdym razem, gdy uzyskasz dostęp do dowolnego elementu wynikowego zakresu.
Oznacza to, że za każdym razem, gdy odwołujesz się do elementu t
, ponownie wywołujesz new Thread() { ... }
. Ponieważ robisz to dwa razy, a zakres ma 5 elementów, tworzysz 10 wątków. Zaczynasz na pierwszej 5, i dołącz na drugim 5.
Jeśli jest to mylące, spojrzeć na poniższy przykład:
scala> object test {
| val t = for (i <- 1 to 5) yield { println("Called again! "+i); i }
| }
defined module test
scala> test.t
Called again! 1
Called again! 2
Called again! 3
Called again! 4
Called again! 5
res4: scala.collection.generic.VectorView[Int,Vector[_]] = RangeM(1, 2, 3, 4, 5)
scala> test.t
Called again! 1
Called again! 2
Called again! 3
Called again! 4
Called again! 5
res5: scala.collection.generic.VectorView[Int,Vector[_]] = RangeM(1, 2, 3, 4, 5)
każdym razem drukować t
(poprzez Scala rEPL drukiem res4
i res5
), wyrażone wyrażenie zostanie ocenione ponownie. Zdarza się dla poszczególnych elementów TOO:
scala> test.t(1)
Called again! 2
res6: Int = 2
scala> test.t(1)
Called again! 2
res7: Int = 2
EDIT
Jak Scala 2.8, Range
będzie surowe, więc kod w pytaniu będzie działać jak pierwotnie oczekiwano.
Podtrzymuję tę kwestię, ponieważ specyficzna interakcja for-comprehensions, zakresów i wątków wydaje się być częstym powtarzającym się wzorem błędu. –