2012-11-21 3 views
3

F #paralléliser création de tableau

[|for index in 1 .. items.Count()-1 -> (* create object here - complex operations *)|] 

C#

Object[] newItemArray= new Object[items.Count]; 

Parallel.For(0, items.Count, index=> 
{ 
    /*complex stuff here*/ 
    newItemArray[index] = new Object(); 
}); 

J'ai ci-dessus C# et F # faire la même chose. Sans le Parallel.For, le F # est légèrement plus rapide. Avec le Parallel.For, le C# prend moitié moins de temps à s'exécuter. Comment paralléliser correctement le F # pour obtenir le même boost de performance que le C#? La façon dont j'ai essayé jusqu'ici était Array.Parallel.Iteri, donc je pourrais utiliser le même index dans un truc de tableau que j'ai utilisé en C#, mais il l'a ralenti au lieu de l'accélérer.

Edit:

Plus de détails sur ce que je fais:

J'ai un dénombrable de byte array array array. J'ai un autre byte array array array auquel je compare les autres. Je suis en train de trier l'énumérable sur% similarity et de renvoyer les 500 premiers.

Dans les deux F # et C# je fais une simple boucle imbriquée qui incrémente un compteur. Une fois la boucle bouclée sur un élément particulier de mon énumérable, je crée un tuple de (item, counter). Une fois que j'ai créé mon nouvel élément énumérable de (item, counter), je le trierai sur la variable du compteur, récupèrerai les 500 premiers et ensuite je les convertirai en un élément énumérable.

La partie que je suis en train de l'intérieur du Parallel.For est la création du IEnumerable<Tuple<item, int>>

+0

Je suppose qu'il est temps de commencer à comparer IL ... – mydogisbox

+0

Je sais que ce n'est pas facile mais pouvez-vous donner un exemple reproductible? Vous * Edit * n'aide pas beaucoup. – pad

Répondre

3

Vous ne devriez pas utiliser la compréhension du tableau dans ce cas. C'est un peu plus lent que les fonctions de haut niveau et ne peut pas être parallélisé.

Bien que je préférerais @ solution de ildjarn, voici une solution équivalente à votre C# un:

// You need an uninitialized array to fill in later 
let newItemArray = Array.zeroCreate items.Count 

// Fill in the array in a parallel manner 
Array.Parallel.iteri (fun i v -> 
    (* create object here - complex operations *)) newItemArray 

Vous pouvez également utiliser Parallel.For directement:

let newItemArray = Array.zeroCreate items.Count 

Parallel.For(0, items.Count, 
      (fun index -> 
       (* complex stuff here *) 
       newItemArray.[index] <- Object()) 
) |> ignore 

Il est plus bavard, mais donne vous avez plus de contrôle sur degree of parallelism.

+0

'iteri' est la première méthode que j'ai essayé et n'est que légèrement plus lente que ma solution séquentielle. La solution 'Parallel.For' prend environ 3,5 fois plus de temps que ma solution séquentielle. – mydogisbox

+0

Pouvez-vous comparer rapidement les solutions parallèles et séquentielles dans F # Interactive avec '#time 'sur" ;; '? Il est difficile de deviner sans plus de détails. – pad

+0

J'ai un chronomètre autour d'eux. Les temps sont: 1.025 pour la solution 'Parallel.For' et .436 pour la solution' iteri'. Ma solution séquentielle F # tourne à environ .360 à chaque fois. – mydogisbox

5
Array.Parallel.init items.Count (fun index -> 
    (* create object here - complex operations *)) 

Documentation officielle: Parallel.init<'T> Function (F#)

+0

+1, ce serait ma solution préférée mais vous êtes plus rapide. – pad

+0

@pad: Pas forcément plus rapide, il manque juste des détails. :-P – ildjarn

+0

Pour une raison quelconque, cela prend 3 fois plus de temps que ma solution séquentielle et 7 fois plus de temps que ma solution C# parallèle. – mydogisbox