スポンサーサイト

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

F#入門中級編第17回(Asynchronous Workflows(3))

今回のお題は「Asynchronous Workflows(3) 」です。
 
さて今回はまず、非同期処理が良く使われる場面であるディスクの読みとりの例を考えてみます。
まずは同期処理でファイル名を与えて、それの総バイト数と2番目の一バイトを表す関数を定義してみます。
 
//同期処理版
let openAndLookIntoFile fileName =     
    use fs = new FileStream(fileName,FileMode.Open, FileAccess.Read, FileShare.Read)
    let data = Array.create (int fs.Length) 0uy  //配列の初期化
    let bytesRead = fs.Read(data, 0, data.Length)     
    printfn "Read Bytes: %d, The first byte was: %i "          
        bytesRead data.[1]
        
まずReadメソッドですがパラメーターと戻り値は次のようになります。
 
array 
このメソッドが戻るとき、指定したバイト配列の offset から (offset + count - 1) までの値が、現在のソースから読み取られたバイトに置き換えられます。 
offset 
読み取りの開始位置を示す array 内のバイト オフセット。 
count 
読み取る最大バイト数。 
戻り値
バッファに読み取られた合計文字数
 
その他の部分は特に問題ないかと思います。
 
さてこれを非同期処理にする場合にどうすればよいかというと、FileStreamに準備されている非同期処理用のメソッドを利用します。
BeginOperationNameに相当するのがBeginReadで、上のReadメソッドの3つのパラメータに加えて、「処理が終了したときにIAsyncResultオブジェクトに対してどういう処理をするのか」を記述したコールバック関数(特に明示的にAsyncCallbackとしてラップしなくても大丈夫のようです)、および「開始前にIAsyncResultオブジェクトへ付加するユーザー定義情報」という二つのパラメータが追加されています。
EndOperationNameに相当するのがEndReadで引数はIAsyncResultオブジェクトで、返り値は「バッファに読み取られた合計文字数」です。これを上のコールバック関数内で呼び出すことにします。
 
それではコードを示します。
 
//非同期処理版
let openFileASyn fileName =     
    let fs = new FileStream(fileName,FileMode.Open, FileAccess.Read, FileShare.Read)     
    let data = Array.create (int fs.Length) 0uy     
    let callback ar =         
        let bytesRead = fs.EndRead(ar)         
        fs.Dispose()         
        printfn "Read Bytes: %d, The first byte was: %i "  bytesRead data.[1]      
    fs.BeginRead(data, 0, data.Length, (fun ar -> callback ar),null) |> ignore
 
さて、F#のAsynchronous Workflowsを利用すると、明示的にコールバックデリゲイトをコーディングすることなく非同期処理を行うことができます。
 
それではとりあえず、Asynchronous Workflows版をみてください。
 
//Asynchronous Workflows版
let  openFilendLookIntoFileASynWorkflow fileName =     
    async { use  fs = new  FileStream(fileName,FileMode.Open, FileAccess.Read, FileShare.Read)
            let  data = Array.create (int fs.Length) 0uy   
            let!  bytesRead = fs.AsyncRead(data, 0, data.Length)
            do  printfn "Read Bytes: %i, The first byte was: %i" bytesRead data.[1] }
 
まず目につくのが全体がasync{}で囲まれていることですが、これはcomputation expressionの特殊な場合ということです。次にuseとlet!の使用です。computation expressionでやったように、右辺のfs.AsyncRead(data, 0, data.Length)から、左辺のbytesReadに行くまでに、カスタム化されたmember.BindとAsynRead関数のコンビネーションが「継続渡し形式」を使って、非同期処理をうまくラップしているのだろうなと予想して頂ければと思います。
 
さてこの関数の型はstring -> Async<unit>となります。stringは引数であるファイル名ですが、問題は返り値のAsyn<unit>(<>内のunitは非同期処理の結果の型を表します)とは何かということです。これは非同期処理の実行単位で、定義しただけでは非同期処理は実行されません。実行方法は色々あるのですが、いくつか紹介します。
 
(1)RunSynchronously  型 Asyn<'a> -> 'a
    バックグラウンドでworkflowをはしらせます。これは呼び出し側のスレッドをこのworkflowの実行が終わるまで待機させます。(引数にタイムアウトの時間を加えることもできます。)
    
実行例
 
> Async.RunSynchronously (openFilendLookIntoFileASynWorkflow @"C:\Program Files\Internet Explorer\iexplore.exe");;
 
Read Bytes: 638216, The first byte was: 90
val it : unit = ()
 
(2)Start 型 Asyn<unit> -> unit
    スレッドプールで実行します。結果は待ちません。
    
実行例
> Async.Start (openFilendLookIntoFileASynWorkflow @"C:\Program Files\Internet Explorer\iexplore.exe");;
val it : unit = ()
 
>
Read Bytes: 638216, The first byte was: 90
 
(3)Parallel 型seq<Async<'a>> -> Async<array<'a>>
    複数の非同期処理を一つにまとめます。
    
実行例
 
>let  openFilendLookIntoFileASynWorkflow fileName =     
    async { use  fs = new  FileStream(fileName,FileMode.Open, FileAccess.Read, FileShare.Read)
            let  data = Array.create (int fs.Length) 0uy   
            let!  bytesRead = fs.AsyncRead(data, 0, data.Length)
            return bytesRead };;
 
>let k = seq{ yield (openFilendLookIntoFileASynWorkflow @"C:\Program Files\Internet Explorer\iexplore.exe")
             yield (openFilendLookIntoFileASynWorkflow @"C:\Program Files\Internet Explorer\ExtExport.exe")};;
 
> printfn "%A" (Async.RunSynchronously(Async.Parallel k));;
[|638216; 144384|]
val it : unit = ()    
 
Parrallelを使ってから、実行すると、スレッドプールに適当数のスレッドを投げ込みながら実行してくれます。
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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