2013-05-24 6 views
7

I this function haben eine Array zu einem ParArray, was die Anzahl der Threads als Parameter zu konvertieren:generische Typparameter für die Umwandlung in parallele Sammlung

def parN[T](collection: Array[T], n: Int) = { 
    val parCollection = collection.par 
    parCollection.tasksupport = new ForkJoinTaskSupport(
     new concurrent.forkjoin.ForkJoinPool(n)) 
    parCollection 
} 

Nun möchte Ich mag diese generisch machen, so dass es arbeitet mit Sammlungen anderer als Array:

def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S], n: Int) = { 
    val parCollection = collection.par 
    parCollection.tasksupport = new ForkJoinTaskSupport(
     new concurrent.forkjoin.ForkJoinPool(n)) 
    parCollection 
} 

Aber when I call it mit parN(Array(1, 2, 3), 2), bekomme ich diesen Fehler:

inferred type arguments [Int,Array] do not 
conform to method parN's type parameter bounds 
[S,T[S] <: scala.collection.Parallelizable[S,scala.collection.parallel.ParIterable[S]]] 

Auf der anderen Seite, das funktioniert:

val x: Parallelizable[Int, ParIterable[Int]] = Array(1, 2, 3) 

Irgendwelche Ideen, was mit meiner Art Parameter falsch sein könnte?

Antwort

5

Beachten Sie, dass dies ein Problem speziell für Array ist: Ihre Methode funktioniert für List oder eine andere normale Sammlung (außer solche mit mehreren Typparameter oder keine). Beispiel:

scala> parN(List(1,2,3), 2) 
res17: scala.collection.parallel.ParIterable[Int] = ParVector(1, 2, 3) 

scala> parN(Set(1,2,3), 2) 
res18: scala.collection.parallel.ParIterable[Int] = ParSet(1, 2, 3) 

Array ist immer ein besonderer Fall, wenn es um Sammlungen kommt, weil ... es ist nicht eine Sammlung ist. Aufgrund von Java ist die Definition final class Array[T] extends Serializable with Cloneable. Es gibt jedoch zwei implicits, die überall verfügbar sind und die Array in einen Sammlungs-Typ (ArrayOps und) konvertieren können. Und diese Art Parallelizable tun implementieren, so sollte alles in Ordnung sein ... außer Typinferenz in die Quere kommt:

Ihre Art Parameter nur als T[S] definiert ist, so dass, wenn ein Array[Int] empfangen werden, wird gerne Array[Int] schließen, und dann Überprüfen Sie die Grenzen: Fehler, Array erstreckt sich nicht Parallelizable. Spiel ist aus.

Ich sehe zwei Möglichkeiten:

  • Sie explizit kann sagen, dass Sie ein Parallelizable:

    def parN[S](collection: Parallelizable[S, ParIterable[S]], n: Int) 
    

    Oder wenn Sie Zugriff auf die eigentliche Art benötigen T (in Ihrem Fall nicht, aber wer weiß):

    def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S] with 
        Parallelizable[S, ParIterable[S]], n: Int) 
    
  • oder Sie können anythin g, die implizit in einen Parallelizable umgewandelt werden kann, einen impliziten Parameter verwendet:

    def parN[S, T <% Parallelizable[S, ParIterable[S]]](collection: T, n: Int) 
    

    , die die kurze Version ist:

    def parN[S, T](collection: T, n: Int)(implicit ev: T => 
        Parallelizable[S, ParIterable[S]]) 
    

Alle diese funktionieren sollte. In Ihrem Fall würde ich den allerersten empfehlen: Es ist der am besten lesbare, der die Arbeit erledigt.

+0

Wow, schlag mich dazu. Das Typklassenmuster ist der Weg dorthin. Müssen Sie jedoch nicht eine 'Manifest'-Anforderung hinzufügen, um mit Arrays zu arbeiten? – wheaties

+1

@wheaties no a 'Manifest \ ClassTag' wird nicht einmal benötigt, da seine Methode kein Array erzeugt (' Parallelizable.par' benötigt kein Manifest, es kann immer eine Par-Collection erstellen). Und im Fall von Arrays wird nur das ursprüngliche Array umbrochen, es wird nicht einmal kopiert. – gourlaysama

+0

Danke für die detaillierte Antwort, ich benutze eine '<%' Ansicht gebunden in 'CustomParallelizable'. – ValarDohaeris

Verwandte Themen