Skip to content
Browse files

Merge branch 'master' of

  • Loading branch information...
2 parents e30272b + 59afeb1 commit 6e723494f285bd7f75cbf2beb26b76c2ef2df15a @heathermiller heathermiller committed Aug 30, 2012
2 cheatsheets/
@@ -57,6 +57,8 @@ about: Thanks to <a href="">Brendan O'Connor</a>, this cheat
| `for ((x,y) <- xs zip ys) yield x*y` _same as_ <br>`(xs zip ys) map { case (x,y) => x*y }` | for comprehension: destructuring bind |
| `for (x <- xs; y <- ys) yield x*y` _same as_ <br>`xs flatMap {x => ys map {y => x*y}}` | for comprehension: cross product |
| `for (x <- xs; y <- ys) {`<br> `println("%d/%d = %.1f".format(x,y, x*y))`<br>`}` | for comprehension: imperative-ish<br>[sprintf-style]( |
+| `for (i <- 1 to 5) {`<br> `println(i)`<br>`}` | for comprehension: iterate including the upper bound |
+| `for (i <- 1 until 5) {`<br> `println(i)`<br>`}` | for comprehension: iterate omitting the upper bound |
| <h2 id="pattern_matching">pattern matching</h2> | |
| <span class="label success">Good</span> `(xs zip ys) map { case (x,y) => x*y }`<br> <span class="label important">Bad</span> `(xs zip ys) map( (x,y) => x*y )` | use case in function args for pattern matching. |
| <span class="label important">Bad</span><br>`val v42 = 42`<br>`Some(3) match {`<br>` case Some(v42) => println("42")`<br>` case _ => println("Not 42")`<br>`}` | "v42" is interpreted as a name matching any Int value, and "42" is printed. |
36 de/tutorials/tour/
@@ -0,0 +1,36 @@
+layout: tutorial
+title: Polymorphe Methoden
+disqus: true
+tutorial: scala-tour
+num: 21
+language: de
+Methoden in Scala können sowohl in deren Parametern als auch in deren Typen parametrisiert werden.
+Wie bei Klassen werden die Parameter von runden Klammern umschlossen, während Typ-Parameter in
+eckigen Klammern deklariert werden. Das folgende Beispiel demonstriert dies:
+ object PolyTest extends App {
+ def dup[T](x: T, n: Int): List[T] =
+ if (n == 0)
+ Nil
+ else
+ x :: dup(x, n - 1)
+ println(dup[Int](3, 4))
+ println(dup("three", 3))
+ }
+Die Methode `dup` des Objektes `PolyTest` ist im Typ `T` sowie den Parametern `x: T` und `n: Int`
+parametrisiert. Wenn die Methode `dup` aufgerufen wird, können Typ-Parameter einerseits explizit
+angegeben werden, wie in Zeile 8, andererseits kann man sie auslassen, wie in Zeile 9, und von
+Scalas Typ-System inferieren lassen. Diese inferierten Typen stammen von den Typen der übergebenen
+Argumente, in obigem Beispiel der Wert `"three"` vom Typ `String`.
+Zu bemerken ist, dass der Trait `App` dafür entwickelt worden ist, kurze Testprogramme zu schreiben,
+jedoch für wirklich produktiv gehenden Quellcode der Scala Versionen 2.8.x und früher vermieden
+werden sollte. An dessen Stelle sollte die Methode `main` verwendet werden.
67 es/overviews/parallel-collections/
@@ -1,6 +1,6 @@
layout: overview-large
-title: Configuring Parallel Collections
+title: Configurando las colecciones paralelas
disqus: true
@@ -9,29 +9,28 @@ num: 7
language: es
-## Task support
+## "Task support"
-Parallel collections are modular in the way operations are scheduled. Each
-parallel collection is parametrized with a task support object which is
-responsible for scheduling and load-balancing tasks to processors.
+Las colecciones paralelas son modulares respecto al modo en que las operaciones
+son planificadas. Cada colección paralela es planificada con un objeto "task support"
+el cual es responsable de la planificación y el balanceo de las tareas a los
+distintos procesadores.
-The task support object internally keeps a reference to a thread pool
-implementation and decides how and when tasks are split into smaller tasks. To
-learn more about the internals of how exactly this is done, see the tech
-report \[[1][1]\].
+El objeto "task support" mantiene internamente un referencia a un pool de hilos y decide
+cómo y cuando las tareas son divididas en tareas más pequeñas. Para conocer más en detalle
+cómo funciona internamente diríjase al informe técnico \[[1][1]\].
-There are currently a few task support implementations available for parallel
-collections. The `ForkJoinTaskSupport` uses a fork-join pool internally and is
-used by default on JVM 1.6 or greater. The less efficient
-`ThreadPoolTaskSupport` is a fallback for JVM 1.5 and JVMs that do not support
-the fork join pools. The `ExecutionContextTaskSupport` uses the default
-execution context implementation found in `scala.concurrent`, and it reuses
-the thread pool used in `scala.concurrent` (this is either a fork join pool or
-a thread pool executor, depending on the JVM version). The execution context
-task support is set to each parallel collection by default, so parallel
-collections reuse the same fork-join pool as the future API.
+En la actualidad las colecciones paralelas disponen de unas cuantas implementaciones de
+"task support". El `ForkJoinTaskSupport` utiliza internamente un fork-join pool y es utilizado
+por defecto en JVM 1.6 o superiores. `ThreadPoolTaskSupport`, menos eficiente, es utilizado como
+mecanismo de reserva para JVM 1.5 y máquinas virtuales que no soporten los fork join pools. El
+`ExecutionContextTaskSupport` utiliza el contexto de ejecución por defecto que viene definido
+en `scala.concurrent`, y reutiliza el thread pool utilizado en dicho paquete (podrá ser un fork
+join pool o un thread pool executor dependiendo de la versión de la JVM). El "task support" basado
+en el contexto de ejecución es establecido en cada una de las colecciones paralelas por defecto, de modo
+que dichas colecciones reutilizan el mismo fork-join pool del mismo modo que el API de las "futures".
-Here is a way to change the task support of a parallel collection:
+A continuación se muestra cómo se puede modificar el objeto "task support" de una colección paralela:
scala> import scala.collection.parallel._
import scala.collection.parallel._
@@ -45,37 +44,37 @@ Here is a way to change the task support of a parallel collection:
scala> pc map { _ + 1 }
res0: scala.collection.parallel.mutable.ParArray[Int] = ParArray(2, 3, 4)
-The above sets the parallel collection to use a fork-join pool with
-parallelism level 2. To set the parallel collection to use a thread pool
+El fragmento de código anterior determina que la colección paralela utilice un fork-join pool con un nivel 2 de
+paralelismo. Para indicar que la colección utilice un thread pool executor tendremos que hacerlo del siguiente modo:
scala> pc.tasksupport = new ThreadPoolTaskSupport()
pc.tasksupport: scala.collection.parallel.TaskSupport = scala.collection.parallel.ThreadPoolTaskSupport@1d914a39
scala> pc map { _ + 1 }
res1: scala.collection.parallel.mutable.ParArray[Int] = ParArray(2, 3, 4)
-When a parallel collection is serialized, the task support field is omitted
-from serialization. When deserializing a parallel collection, the task support
-field is set to the default value-- the execution context task support.
+Cuando una colección paralela es serializada, el atributo que almacena la referencia
+al objeto "task support" es omitido en el proceso de serialización. Cuando una colección
+paralela es deserializada, dicho atributo toma el valor por defecto -- el objeto "task support"
+basado en el contexto de ejecución.
-To implement a custom task support, extend the `TaskSupport` trait and
-implement the following methods:
+Para llevar a cabo una implementación personalizada de un nuevo objeto "task support" necesitamos
+extender del trait `TaskSupport` e implementar los siguientes métodos:
def execute[R, Tp](task: Task[R, Tp]): () => R
def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R
def parallelismLevel: Int
-The `execute` method schedules a task asynchronously and returns a future to
-wait on the result of the computation. The `executeAndWait` method does the
-same, but only returns when the task is completed. The `parallelismLevel`
-simply returns the targeted number of cores that the task support uses to
-schedule tasks.
+El método `execute` planifica una tarea asíncrona y retorna una "future" sobre la que
+esperar el resultado de la computación. El método `executeAndWait` lleva a cabo el mismo
+trabajo, pero retorna única y exclusivamente una vez la tarea haya finalizado. `parallelismLevel`
+simplemente retorna el número de núcleos que el objeto "task support" utiliza para planificar
+las diferentes tareas.
-## References
+## Referencias
1. [On a Generic Parallel Collection Framework, June 2011][1]
73 es/overviews/parallel-collections/
@@ -1,68 +1,65 @@
layout: overview-large
-title: Parallel Collection Conversions
+title: Conversiones en colecciones paralelas
disqus: true
partof: parallel-collections
num: 3
language: es
-## Converting between sequential and parallel collections
+## Conversiones entre colecciones secuenciales y paralelas
-Every sequential collection can be converted to its parallel variant
-using the `par` method. Certain sequential collections have a
-direct parallel counterpart. For these collections the conversion is
-efficient-- it occurs in constant time, since both the sequential and
-the parallel collection have the same data-structural representation
-(one exception is mutable hash maps and hash sets which are slightly
-more expensive to convert the first time `par` is called, but
-subsequent invocations of `par` take constant time). It should be
-noted that for mutable collections, changes in the sequential collection are
-visible in its parallel counterpart if they share the underlying data-structure.
+Cada una de las colecciones secuenciales puede convertirse es su versión
+paralela mediante la utilización del método `par`. Determinadas colecciones
+secuenciales disponen de una versión homóloga paralela. Para estas colecciones el
+proceso de conversión es eficiente -- ocurre en tiempo constante dado que ambas
+versiones utilizan la misma estructura de datos interna. Una excepción al caso
+anterior es el caso de los hash maps y hash sets mutables, donde el proceso de
+conversión es un poco más costoso la primera vez que el método `par` es llamado,
+aunque las posteriores invocaciones de dicho método ofrecerán un tiempo de ejecución
+constante. Nótese que en el caso de las colecciones mutables, los cambios en la
+colección secuencial son visibles en su homóloga paralela en el caso de que compartan
+la estructura de datos subyacente.
-| Sequential | Parallel |
+| Secuencial | Paralelo |
| ------------- | -------------- |
| **mutable** | |
| `Array` | `ParArray` |
| `HashMap` | `ParHashMap` |
| `HashSet` | `ParHashSet` |
| `TrieMap` | `ParTrieMap` |
-| **immutable** | |
+| **inmutable** | |
| `Vector` | `ParVector` |
| `Range` | `ParRange` |
| `HashMap` | `ParHashMap` |
| `HashSet` | `ParHashSet` |
-Other collections, such as lists, queues or streams, are inherently sequential
-in the sense that the elements must be accessed one after the other. These
-collections are converted to their parallel variants by copying the elements
-into a similar parallel collection. For example, a functional list is
-converted into a standard immutable parallel sequence, which is a parallel
-Every parallel collection can be converted to its sequential variant
-using the `seq` method. Converting a parallel collection to a
-sequential collection is always efficient-- it takes constant
-time. Calling `seq` on a mutable parallel collection yields a
-sequential collection which is backed by the same store-- updates to
-one collection will be visible in the other one.
+Otro tipo de colecciones, como las listas, colas o `streams`, son inherentemente
+secuenciales en el sentido de que los elementos deben ser accedidos uno tras otro.
+La versión paralela de estas estructuras se obtiene mediante la copia de los elementos
+en una colección paralela. Por ejemplo, una lista funcional es convertida en una
+secuencia paralela inmutable; un vector paralelo.
+Cada colección paralela puede ser convertida a su variante secuencial mediante el uso
+del método `seq`. La conversión de una colección paralela a su homóloga secuencial es
+siempre un proceso eficiente -- tiempo constante. La invocación del método `seq` sobre
+una colección paralela mutable retorna una colección secuencial cuya representación interna
+es la misma que la de la versión paralela, por lo que posibles actualizaciones en una de las
+colecciones serán visibles en la otra.
-## Converting between different collection types
+## Conversiones entre diferentes tipo de colecciones
-Orthogonal to converting between sequential and parallel collections,
-collections can be converted between different collection types. For
-example, while calling `toSeq` converts a sequential set to a
-sequential sequence, calling `toSeq` on a parallel set converts it to
-a parallel sequence. The general rule is that if there is a
-parallel version of `X`, then the `toX` method converts the collection
-into a `ParX` collection.
+Ortogonal a la conversión entre colecciones secuenciales y paralelas, las colecciones
+pueden convertirse entre diferentes tipos. Por ejemplo, la llamada al método `toSeq`
+convierte un conjunto secuencial en una secuencia secuencial, mientras que si invocamos
+dicho método sobre un conjunto paralelo obtendremos una secuencia paralela. La regla
+general is que si existe una versión paralela de `X`, el método `toX` convierte la colección
+en una colección `ParX`
-Here is a summary of all conversion methods:
+A continuación se muestra un resumen de todos los métodos de conversión:
-| Method | Return Type |
+| método | Tipo de Retorno|
| -------------- | -------------- |
| `toArray` | `Array` |
| `toList` | `List` |
292 es/overviews/parallel-collections/
@@ -1,6 +1,6 @@
layout: overview-large
-title: Measuring Performance
+title: Midiendo el rendimiento
disqus: true
@@ -12,72 +12,69 @@ language: es
## Performance on the JVM
-The performance model on the JVM is sometimes convoluted in commentaries about
-it, and as a result is not well understood. For various reasons, some code may
-not be as performant or as scalable as expected. Here, we provide a few
-One of the reasons is that the compilation process for a JVM application is
-not the same as that of a statically compiled language (see \[[2][2]\]). The
-Java and Scala compilers convert source code into JVM bytecode and do very
-little optimization. On most modern JVMs, once the program bytecode is run, it
-is converted into machine code for the computer architecture on which it is
-being run. This is called the just-in-time compilation. The level of code
-optimization is, however, low with just-in-time compilation, since it has to
-be fast. To avoid recompiling, the so called HotSpot compiler only optimizes
-parts of the code which are executed frequently. What this means for the
-benchmark writer is that a program might have different performance each time
-it is run. Executing the same piece of code (e.g. a method) multiple times in
-the same JVM instance might give very different performance results depending
-on whether the particular code was optimized in between the runs.
-Additionally, measuring the execution time of some piece of code may include
-the time during which the JIT compiler itself was performing the optimization,
-thus giving inconsistent results.
-Another hidden execution that takes part on the JVM is the automatic memory
-management. Every once in a while, the execution of the program is stopped and
-a garbage collector is run. If the program being benchmarked allocates any
-heap memory at all (and most JVM programs do), the garbage collector will have
-to run, thus possibly distorting the measurement. To amortize the garbage
-collection effects, the measured program should run many times to trigger many
-garbage collections.
-One common cause of a performance deterioration is also boxing and unboxing
-that happens implicitly when passing a primitive type as an argument to a
-generic method. At runtime, primitive types are converted to objects which
-represent them, so that they could be passed to a method with a generic type
-parameter. This induces extra allocations and is slower, also producing
-additional garbage on the heap.
-Where parallel performance is concerned, one common issue is memory
-contention, as the programmer does not have explicit control about where the
-objects are allocated.
-In fact, due to GC effects, contention can occur at a later stage in
-the application lifetime after objects get moved around in memory.
-Such effects need to be taken into consideration when writing a benchmark.
-## Microbenchmarking example
-There are several approaches to avoid the above effects during measurement.
-First of all, the target microbenchmark must be executed enough times to make
-sure that the just-in-time compiler compiled it to machine code and that it
-was optimized. This is known as the warm-up phase.
-The microbenchmark itself should be run in a separate JVM instance to reduce
-noise coming from garbage collection of the objects allocated by different
-parts of the program or unrelated just-in-time compilation.
-It should be run using the server version of the HotSpot JVM, which does more
-aggressive optimizations.
-Finally, to reduce the chance of a garbage collection occurring in the middle
-of the benchmark, ideally a garbage collection cycle should occur prior to the
-run of the benchmark, postponing the next cycle as far as possible.
-The `scala.testing.Benchmark` trait is predefined in the Scala standard
-library and is designed with above in mind. Here is an example of benchmarking
-a map operation on a concurrent trie:
+Algunas veces el modelo de rendimiento de la JVM se complica debido a comentarios
+sobre el mismo, y como resultado de los mismos, se tienen concepciones equívocas del mismo.
+Por diferentes motivos, determinado código podría ofrecer un rendimiento o escalabilidad
+inferior a la esperada. A continuación ofrecemos algunos ejemplos.
+Uno de los principales motivos es que el proceso de compilación de una aplicación que se
+ejecuta sobre la JVM no es el mismo que el de un lenguaje compilado de manera estática
+(véase \[[2][2]\]). Los compiladores de Java y Scala traducen el código fuente en *bytecode* y
+el conjunto de optimizaciones que llevan a cabo es muy reducido. En la mayoría de las JVM
+modernas, una vez el bytecode es ejecutado, se convierte en código máquina dependiente de la
+arquitectura de la máquina subyacente. Este proceso es conocido como compilación "just-int-time".
+Sin embargo, el nivel de optimización del código es muy bajo puesto que dicho proceso deber ser
+lo más rápido posible. Con el objetivo de evitar el proceso de recompilación, el llamado
+compilador HotSpot optimiza únicamente aquellas partes del código que son ejecutadas de manera
+frecuente. Esto supone que los desarrolladores de "benchmarks" deberán ser conscientes que los
+programas podrían presentar rendimientos dispares en diferentes ejecuciones. Múltiples ejecuciones
+de un mismo fragmento de código (por ejemplo un método) podrían ofrecer rendimientos dispares en función de
+si se ha llevado a cabo un proceso de optimización del código entre dichas ejecuciones. Adicionalmente,
+la medición de los tiempos de ejecución de un fragmento de código podría incluir el tiempo en el que
+el propio compilador JIT lleva a cabo el proceso de optimizacion, falseando los resultados.
+Otro elemento "oculto" que forma parte de la JVM es la gestión automática de la memoria. De vez en cuando,
+la ejecución de un programa es detenida para que el recolector de basura entre en funcionamiento. Si el
+programa que estamos analizando realiza alguna reserva de memoria (algo que la mayoría de programas hacen),
+el recolector de basura podría entrar en acción, posiblemente distorsionando los resultados. Con el objetivo
+de disminuir los efectos de la recolección de basura, el programa bajo estudio deberá ser ejecutado en
+múltiples ocasiones para disparar numerosas recolecciones de basura.
+Una causa muy común que afecta de manera notable al rendimiento son las conversiones implícitas que se
+llevan a cabo cuando se pasa un tipo primitivo a un método que espera un argumento genérico. En tiempo
+de ejecución, los tipos primitivos con convertidos en los objetos que los representan, de manera que puedan
+ser pasados como argumentos en los métodos que presentan parámetros genéricos. Este proceso implica un conjunto
+extra de reservas de memoria y es más lento, ocasionando nueva basura en el heap.
+Cuando nos referimos al rendimiento en colecciones paralelas la contención de la memoria es un problema muy
+común, dado que el desarrollador no dispone de un control explícito sobre la asignación de los objetos.
+De hecho, debido a los efectos ocasionados por la recolección de basura, la contención puede producirse en
+un estado posterior del ciclo de vida de la aplicación, una vez los objetos hayan ido circulando por la
+memoria. Estos efectos deberán ser tenidos en cuenta en el momento en que se esté desarrollando un benchmark.
+## Ejemplo de microbenchmarking
+Numerosos enfoques permiten evitar los anteriores efectos durante el periodo de medición.
+En primer lugar, el microbenchmark debe ser ejecutado el número de veces necesario que
+permita asegurar que el compilador just-in-time ha compilado a código máquina y que
+ha optimizado el código resultante. Esto es lo que comunmente se conoce como fase de
+El microbenchmark debe ser ejecutado en una instancia independiente de la máquina virtual
+con el objetivo de reducir la cantidad de ruido proveniente de la recolección de basura
+de los objetos alocados por el propio benchmark o de compilaciones just-in-time que no
+están relacionadas con el proceso que estamos midiendo.
+Deberá ser ejecutado utilizando la versión servidora de la máquina virtual, la cual lleva a
+cabo un conjunto de optimizaciones mucho más agresivas.
+Finalmente, con el objetivo de reducir la posibilidad de que una recolección de basura ocurra
+durante la ejecución del benchmark, idealmente, debería producirse un ciclo de recolección de basura antes
+de la ejecución del benchmark, retrasando el siguiente ciclo tanto como sea posible.
+El trait `scala.testing.Benchmark` se predefine en la librería estándar de Scala y ha sido diseñado con
+el punto anterior en mente. A continuación se muestra un ejemplo del benchmarking de un operación map
+sobre un "trie" concurrente:
import collection.parallel.mutable.ParTrieMap
import collection.parallel.ForkJoinTaskSupport
@@ -96,76 +93,82 @@ a map operation on a concurrent trie:
-The `run` method embodies the microbenchmark code which will be run
-repetitively and whose running time will be measured. The object `Map` above
-extends the `scala.testing.Benchmark` trait and parses system specified
-parameters `par` for the parallelism level and `length` for the number of
-elements in the trie.
+El método `run` encapsula el código del microbenchmark que será ejecutado de
+manera repetitiva y cuyos tiempos de ejecución serán medidos. El anterior objeto `Map` extiende
+el trait `scala.testing.Benchmark` y parsea los parámetros `par` (nivel de paralelismo) y
+`length` (número de elementos en el trie). Ambos parámetros son especificados a través de
+propiedades del sistema.
-After compiling the program above, run it like this:
+Tras compilar el programa anterior, podríamos ejecutarlo tal y como se muestra a continuación:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=1 -Dlength=300000 Map 10
-The `server` flag specifies that the server VM should be used. The `cp`
-specifies the classpath and includes classfiles in the current directory and
-the scala library jar. Arguments `-Dpar` and `-Dlength` are the parallelism
-level and the number of elements. Finally, `10` means that the benchmark
-should be run that many times within the same JVM.
+El flag `server` indica que la máquina virtual debe ser utiliada en modo servidor. `cp` especifica
+el classpath e incluye todos los archivos __.class__ en el directorio actual así como el jar de
+la librería de Scala. Los argumentos `-Dpar` y `-Dlength` representan el nivel de paralelismo y
+el número de elementos respectivamente. Por último, `10` indica el número de veces que el benchmark
+debería ser ejecutado en una misma máquina virtual.
-Running times obtained by setting the `par` to `1`, `2`, `4` and `8` on a
-quad-core i7 with hyperthreading:
+Los tiempos de ejecución obtenidos estableciendo `par` a los valores `1`, `2`, `4` y `8` sobre un
+procesador quad-core i7 con hyperthreading habilitado son los siguientes:
Map$ 126 57 56 57 54 54 54 53 53 53
Map$ 90 99 28 28 26 26 26 26 26 26
Map$ 201 17 17 16 15 15 16 14 18 15
Map$ 182 12 13 17 16 14 14 12 12 12
-We can see above that the running time is higher during the initial runs, but
-is reduced after the code gets optimized. Further, we can see that the benefit
-of hyperthreading is not high in this example, as going from `4` to `8`
-threads results only in a minor performance improvement.
-## How big should a collection be to go parallel?
-This is a question commonly asked. The answer is somewhat involved.
-The size of the collection at which the parallelization pays of really
-depends on many factors. Some of them, but not all, include:
-- Machine architecture. Different CPU types have different
- performance and scalability characteristics. Orthogonal to that,
- whether the machine is multicore or has multiple processors
- communicating via motherboard.
-- JVM vendor and version. Different VMs apply different
- optimizations to the code at runtime. They implement different memory
- management and synchronization techniques. Some do not support
- `ForkJoinPool`, reverting to `ThreadPoolExecutor`s, resulting in
- more overhead.
-- Per-element workload. A function or a predicate for a parallel
- operation determines how big is the per-element workload. The
- smaller the workload, the higher the number of elements needed to
- gain speedups when running in parallel.
-- Specific collection. For example, `ParArray` and
- `ParTrieMap` have splitters that traverse the collection at
- different speeds, meaning there is more per-element work in just the
- traversal itself.
-- Specific operation. For example, `ParVector` is a lot slower for
- transformer methods (like `filter`) than it is for accessor methods (like `foreach`)
-- Side-effects. When modifying memory areas concurrently or using
- synchronization within the body of `foreach`, `map`, etc.,
- contention can occur.
-- Memory management. When allocating a lot of objects a garbage
- collection cycle can be triggered. Depending on how the references
- to new objects are passed around, the GC cycle can take more or less time.
-Even in separation, it is not easy to reason about things above and
-give a precise answer to what the collection size should be. To
-roughly illustrate what the size should be, we give an example of
-a cheap side-effect-free parallel vector reduce (in this case, sum)
-operation performance on an i7 quad-core processor (not using
-hyperthreading) on JDK7:
+Podemos observar en la tabla anterior que el tiempo de ejecución es mayor durante las
+ejecuciones iniciales, reduciéndose a medida que el código va siendo optimizado. Además,
+podemos ver que el beneficio del hyperthreading no es demasiado alto en este ejemplo
+concreto, puesto que el incremento de `4` a `8` hilos produce un incremento mínimo en
+el rendimiento.
+## ¿Cómo de grande debe ser una colección para utilizar la versión paralela?
+Esta es pregunta muy común y la respuesta es algo complicada.
+El tamaño de la colección a partir de la cual la paralelización merece la pena
+depende de numerosos factores. Algunos de ellos, aunque no todos, son:
+- Arquitectura de la máquina. Diferentes tipos de CPU ofrecen diferente características
+ de rendimiento y escalabilidad. Por ejemplo, si la máquina es multicore o presenta
+ múltiples procesadores comunicados mediante la placa base.
+- Versión y proveedor de la JVM. Diferentes máquinas virtuales llevan a cabo
+ diferentes optimizaciones sobre el código en tiempo de ejecución. Implementan
+ diferente gestion de memoria y técnicas de sincronización. Algunas de ellas no
+ soportan el `ForkJoinPool`, volviendo a `ThreadPoolExecutor`, lo cual provoca
+ una sobrecarga mucho mayor.
+- Carga de trabajo por elemento. Una función o un predicado para una colección
+ paralela determina cómo de grande es la carga de trabajo por elemento. Cuanto
+ menor sea la carga de trabajo, mayor será el número de elementos requeridos para
+ obtener acelaraciones cuando se está ejecutando en paralelo.
+- Uso de colecciones específicas. Por ejemplo, `ParArray` y
+ `ParTrieMap` tienen "splitters" que recorren la colección a diferentes
+ velocidades, lo cual implica que existe más trabajo por elemento en el
+ propio recorrido.
+- Operación específica. Por ejemplo, `ParVector` es mucho más lenta para los métodos
+ de transformación (cómo `filter`) que para métodos de acceso (como `foreach`).
+- Efectos colaterales. Cuando se modifica un area de memoria de manera concurrente o
+ se utiliza la sincronización en el cuerpo de un `foreach`, `map`, etc se puede
+ producir contención.
+- Gestión de memoria. Cuando se reserva espacio para muchos objectos es posible
+ que se dispare un ciclo de recolección de basura. Dependiendo de cómo se
+ distribuyan las referencias de los objetos el ciclo de recolección puede llevar
+ más o menos tiempo.
+Incluso de manera independiente, no es sencillo razonar sobre el conjunto de situaciones
+anteriores y determinar una respuesta precisa sobre cuál debería ser el tamaño de la
+colección. Para ilustrar de manera aproximada cuál debería ser el valor de dicho tamaño,
+a continuación, se presenta un ejemplo de una sencilla operación de reducción, __sum__ en este caso,
+libre de efectos colaterales sobre un vector en un procesador i7 quad-core (hyperthreading
+deshabilitado) sobre JDK7
import collection.parallel.immutable.ParVector
object Reduce extends testing.Benchmark {
@@ -193,8 +196,7 @@ hyperthreading) on JDK7:
-We first run the benchmark with `250000` elements and obtain the
-following results, for `1`, `2` and `4` threads:
+La primera ejecución del benchmark utiliza `250000` elementos y obtiene los siguientes resultados para `1`, `2` y `4` hilos:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=1 -Dlength=250000 Reduce 10 10
Reduce$ 54 24 18 18 18 19 19 18 19 19
@@ -203,18 +205,18 @@ following results, for `1`, `2` and `4` threads:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=4 -Dlength=250000 Reduce 10 10
Reduce$ 62 17 15 14 13 11 11 11 11 9
-We then decrease the number of elements down to `120000` and use `4`
-threads to compare the time to that of a sequential vector reduce:
+Posteriormente se decrementa en número de elementos hasta `120000` y se utilizan `4` hilos para comparar
+el tiempo con la operación de reducción sobre un vector secuencial:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=4 -Dlength=120000 Reduce 10 10
Reduce$ 54 10 8 8 8 7 8 7 6 5
java -server -cp .:../../build/pack/lib/scala-library.jar -Dlength=120000 ReduceSeq 10 10
ReduceSeq$ 31 7 8 8 7 7 7 8 7 8
-`120000` elements seems to be the around the threshold in this case.
+En este caso, `120000` elementos parece estar en torno al umbral.
-As another example, we take the `mutable.ParHashMap` and the `map`
-method (a transformer method) and run the following benchmark in the same environment:
+En un ejemplo diferente, utilizamos `mutable.ParHashMap` y el método `map` (un método de transformación)
+y ejecutamos el siguiente benchmark en el mismo entorno:
import collection.parallel.mutable.ParHashMap
@@ -243,8 +245,7 @@ method (a transformer method) and run the following benchmark in the same enviro
-For `120000` elements we get the following times when ranging the
-number of threads from `1` to `4`:
+Para `120000` elementos obtenemos los siguientes tiempos cuando el número de hilos oscila de `1` a `4`:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=1 -Dlength=120000 Map 10 10
Map$ 187 108 97 96 96 95 95 95 96 95
@@ -253,8 +254,7 @@ number of threads from `1` to `4`:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=4 -Dlength=120000 Map 10 10
Map$ 124 54 42 40 38 41 40 40 39 39
-Now, if we reduce the number of elements to `15000` and compare that
-to the sequential hashmap:
+Ahora, si reducimos el número de elementos a `15000` y comparamos con el hashmap secuencial:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dpar=1 -Dlength=15000 Map 10 10
Map$ 41 13 10 10 10 9 9 9 10 9
@@ -263,22 +263,14 @@ to the sequential hashmap:
java -server -cp .:../../build/pack/lib/scala-library.jar -Dlength=15000 MapSeq 10 10
MapSeq$ 39 9 9 9 8 9 9 9 9 9
-For this collection and this operation it makes sense
-to go parallel when there are above `15000` elements (in general,
-it is feasible to parallelize hashmaps and hashsets with fewer
-elements than would be required for arrays or vectors).
+Para esta colección y esta operacion tiene sentido utilizar la versión paralela cuando existen más
+de `15000` elementos (en general, es factible paralelizar hashmaps y hashsets con menos elementos de
+los que serían requeridos por arrays o vectores).
-## References
+## Referencias
1. [Anatomy of a flawed microbenchmark, Brian Goetz][1]
2. [Dynamic compilation and performance measurement, Brian Goetz][2]
[1]: "flawed-benchmark"
- [2]: "dynamic-compilation"
+ [2]: "dynamic-compilation"
8 overviews/parallel-collections/
@@ -121,6 +121,11 @@ Once done, we output the path from the target to the initial node.
+There is a Game of Life example on GitHub which uses Ctries to
+selectively simulate only those parts of the Game of Life automaton which
+are currently active \[[4][4]\].
+It also includes a Swing-based visualization of the Game of Life simulation,
+in which you can observe how tweaking the parameters affects performance.
The concurrent tries also support a linearizable, lock-free, constant
time `snapshot` operation. This operation creates a new concurrent
@@ -154,12 +159,15 @@ Additionally, size computation for parallel concurrent tries is performed in par
## References
1. [Cache-Aware Lock-Free Concurrent Hash Tries][1]
2. [Concurrent Tries with Efficient Non-Blocking Snapshots][2]
3. [Methods of computing square roots][3]
+4. [Game of Life simulation][4]
[1]: "Ctries-techreport"
[2]: "Ctries-snapshot"
[3]: "babylonian-method"
+ [4]: "game-of-life-ctries"
2 overviews/parallel-collections/
@@ -143,7 +143,7 @@ copying required for these collection types introduces an overhead not
incurred by any other collection types, like `Array`, `Vector`, `HashMap`, etc.
For more information on conversions on parallel collections, see the
-[conversions]({{ site.baseurl }}/overviews/parallel-collections/converesions.html)
+[conversions]({{ site.baseurl }}/overviews/parallel-collections/conversions.html)
and [concrete parallel collection classes]({{ site.baseurl }}/overviews/parallel-collections/concrete-parallel-collections.html)
sections of this guide.
14 sips/pending/_posts/
@@ -97,7 +97,7 @@ of type `Left[Throwable]` otherwise. The `onComplete` method is
parametric in the return type of the callback, but it discards the
result of the callback.
-Coming back to our social network example, lets assume we want to
+Coming back to our social network example, let's assume we want to
fetch a list of our own recent posts and render them to the screen.
We do so by calling the method `getRecentPosts` which returns a `List[String]`:
@@ -131,14 +131,18 @@ To handle failed results, the `onFailure` callback is used:
f onFailure {
case t => render("An error has occured: " + t.getMessage)
- } onSuccess {
+ }
+ f onSuccess {
case posts => for (post <- posts) render(post)
The `onFailure` callback is only executed if the future fails, that
is, if it contains an exception. The `onComplete`, `onSuccess`, and
-`onFailure` methods return the receiver (the future), which allows
-registering multiple callbacks by chaining invocations.
+`onFailure` methods have result type `Unit`, which means invocations
+of these methods cannot be chained. This is an intentional design
+decision which was made to avoid suggesting that chained
+invocations may imply an ordering on the execution of the registered
+callbacks (callbacks registered on the same future are unordered).
Since partial functions have the `isDefinedAt` method, the
`onFailure` method only triggers the callback if it is defined for a
@@ -184,7 +188,7 @@ However, a particular `Future` implementation may have a well-defined
5. In the event that some of the callbacks throw an exception, the
-other callbacks are executed irregardlessly.
+other callbacks are executed regardlessly.
6. In the event that some of the callbacks never complete (e.g. the
callback contains an infinite loop), the other callbacks may not be
2 sips/pending/_posts/
@@ -3,7 +3,7 @@ layout: sip
title: SIP-16 - Self-cleaning Macros
vote-status: postponed
-vote-text: This is in Postponed status, but experimental implemntation expected for 2.10. Additionally the following actions the use of macro identifiers will be deprecated in in 2.10.
+vote-text: This is in Postponed status, but experimental implementation is expected for 2.10. Additionally the use of macro identifiers will be deprecated in 2.10.
13 tutorials/tour/
@@ -11,15 +11,18 @@ num: 21
Methods in Scala can be parameterized with both values and types. Like on the class level, value parameters are enclosed in a pair of parentheses, while type parameters are declared within a pair of brackets.
Here is an example:
object PolyTest extends App {
def dup[T](x: T, n: Int): List[T] =
- if (n == 0) Nil
- else x :: dup(x, n - 1)
+ if (n == 0)
+ Nil
+ else
+ x :: dup(x, n - 1)
println(dup[Int](3, 4))
println(dup("three", 3))
-Method `dup` in object `PolyTest` is parameterized with type `T` and with the value parameters `x: T` and `n: Int`. When method `dup` is called, the programmer provides the required parameters _(see line 5 in the program above)_, but as line 6 in the program above shows, the programmer is not required to give actual type parameters explicitly. The type system of Scala can infer such types. This is done by looking at the types of the given value parameters and at the context where the method is called.
+Method `dup` in object `PolyTest` is parameterized with type `T` and with the value parameters `x: T` and `n: Int`. When method `dup` is called, the programmer provides the required parameters _(see line 8 in the program above)_, but as line 9 in the program above shows, the programmer is not required to give actual type parameters explicitly. The type system of Scala can infer such types. This is done by looking at the types of the given value parameters and at the context where the method is called.
Please note that the trait `App` is designed for writing short test programs, but should be avoided for production code (for Scala versions 2.8.x and earlier) as it may affect the ability of the JVM to optimize the resulting code; please use `def main()` instead.

0 comments on commit 6e72349

Please sign in to comment.
Something went wrong with that request. Please try again.