スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#による並行プログラミング入門(10) PLINQ

 まずはLINQの復習を少し。 
IEnuenrable<'a>(seq<'a>)型の値を引数とする多数のメソッドがSystem.Linq.Enumerable名前空間に定義されていて、例えば 
 
> System.Linq.Enumerable.Select([1;2;3],(fun x -> 2*x));; 
val it : seq<int> = seq [2; 4; 6] 
 
とできるのでした。 
 
また引数のタプルの第一成分であるIEnuenrable<'a>(seq<'a>)型の値のインスタンスメソッドのようにも使えるような仕組みになっていて、 
 
> [1;2;3].Select(fun x -> 2+x);; 
val it : seq<int> = seq [2; 4; 6] 
 
というようにも使えるのでした。 
 
また、 
> open System;; 
> let select f s = Enumerable.Select(s,new Func<_,_>(f));; 
 
val select : ('a -> 'b) -> seq<'a> -> seq<'b> 
 
としておけば 
 
> [1;2;3] 
|> select (fun x -> 2*x);; 
val it : seq<int> = seq [2; 4; 6] 
 
とF#的に書くこともできるのでした。 
 
このようにLINQの素材となるのはIEnumenrable<'a>(seq<'a>)型の値だったのですが、 
IEnuenrable<'a>(seq<'a>)型の値を素材としてそれに対してparallelに処理を加えることができるのがPLINQです。(Parallel LINQ)これはSystem.Linq.ParallelEnumerable名前空間に定義されています。 
例えばこちら側のSelectは 
 
static member Select :  
        source:ParallelQuery<'TSource> *  
        selector:Func<'TSource, 'TResult> -> ParallelQuery<'TResult>  
 
引数のタプルの第一成分がParallelQuery<'TSource>型となっていますが、これはIEnumenrable<'TSource>型の値vにたいしてv.AsParallel()とすることで得ることができます。 
IEnumerable型を並行処理の素材用に変換するわけです。 
よって先ほどの例のPLINQ版は次の様に得ることができます。 
 
> let t = System.Linq.ParallelEnumerable.Select( [1;2;3].AsParallel() ,(fun x -> 2*x));; 
val t : ParallelQuery<int> 
 
> t;; 
val it : ParallelQuery<int> = seq [6; 2; 4] //並行処理なので順番は保障されない。 
 
結果はParallelQuery<_>型なのですがこれはlEnumerableインターフェイスを実装しているので、普通のIEnumerble型としても扱えます。 
 
> Seq.iter (fun x ->printfn "%d" x) t;; 
val it : unit = () 
 
また、これはさらに並行処理の素材としても使えます。 
> System.Linq.ParallelEnumerable.Select( t ,(fun x -> 2*x));; 
val it : ParallelQuery<int> = seq [4; 8; 12] 
 
 
さてLINQでは 
 System.Linq.Enumerable.Select([1;2;3],(fun x -> 2*x)) 
 を 
 [1;2;3].Select(fun x -> 2+x);; 
というように書くことができるのでしたが、PLINQでも同様の仕組みで 
System.Linq.ParallelEnumerable.Select( [1;2;3].AsParallel() ,(fun x -> 2*x)) 
を 
[1;2;3].AsParallel().Select(fun x -> 2*x) 
と書くことができます。 
 
> [1;2;3].AsParallel().Select(fun x -> 2*x);; 
val it : ParallelQuery<int> = seq [2; 4; 6] 
 
lEnumerable型の値の次に.AsParallel()を付けるとLINQのメソッドでなくPLINQのメソッドが呼び出せれるという仕組みになっています。 
 
最後にLINQで 
> let select f s = Enumerable.Select(s,new Func<_,_>(f));; 
val select : ('a -> 'b) -> seq<'a> -> seq<'b> 
 
としておいて 
 
> [1;2;3] 
|> select (fun x -> 2*x);; 
val it : seq<int> = seq [2; 4; 6] 
 
とF#的に書くことのPLINQ版ですが、 
 
> open System.Collections.Generic 
let p_select f (s:IEnumerable<'a>) = ParallelEnumerable.Select(s.AsParallel(),new Func<_,_>(f));; 
 
val p_select : 
  ('a -> 'a0) -> Collections.Generic.IEnumerable<'a> -> ParallelQuery<'a0> 
 
としておけば、 
 
> [1;2;3] 
|> p_select (fun x -> 2*x);; 
val it : ParallelQuery<int> = seq [2; 6; 4] 
 
とできます。 
 
(参考) 
実はこれを一般化したものがpseqモジュールとしてF# PowerPackに準備されています 
 
部分抜粋すると 
 
// Type abbreviation for parallel sequences. 
type pseq<'T> = ParallelQuery<'T> 
 
module PSeq =  
 
   // Converst a seq<'T> to a pseq<'T>. 
   //ParallelQuery<'T>型にすでに変換されていれば、そのままで、変換されていなければ変換する 
   let inline toP (s : seq<'T>) =  
       match s with 
       | :? pseq<'T> as p ->  p 
       | _ -> s.AsParallel() 
 
   let map f s  =  
       ParallelEnumerable.Select(toP(s), new Func<_,_>(f))  
 
となってます。 
 
これを使うと先ほどの例は 
 
[1;2;3] 
|> PSeq.map (fun x -> 2*x) 
 
となります。 
 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。