Subscribed unsubscribe Subscribe Subscribe

F# Monkey

about

(F#) async のメモ

Async<'T>に関してのちょっとしたメモ

0. Prepare

async{...} とすると Async<'T>になる

.

let!とかdo!とかのbang!Asyncをはぎとる。つまりAsync<’T>’Tに、Async<Async<’T>>Async<’T>`になる。

1. RunSynchronously and Start

async blockをバックグラウンドで実行させるかどうかのメソッド .

バックグラウンドで実行させない

// always hello world

async{
    stdout.WriteLine("hello")
}|> Async.RunSynchronously

stdout.WriteLine("world")

バックグラウンドで実行させる

// hello world or world hello or world

async{
    stdout.WriteLine("hello")
}|> Async.Start

stdout.WriteLine("world")

2. Parallel

実行順序は保証されない

// hello world or world hello
let hello1 = async { stdout.WriteLine("hello") }
let world1 = async { stdout.WriteLine("world") }

[hello1;world1]
|> Async.Parallel
|> Async.RunSynchronously

実行順序は保証されないがリストの場所は保証される

// ["hello";"world"]
let hello2 = async { return "hello" }
let world2 = async { return "world" }

[hello2;world2]
|> Async.Parallel
|> Async.RunSynchronously
|> printfn "%A"

3. Order in async block

async blockの中は上から下に実行される

// hello world

let hello = async { do stdout.WriteLine("hello") }
let world = async { do stdout.WriteLine("world") }

async {
    do! hello
    do! world
} |> Async.RunSynchronously

4. Wait async (StartChild)

StartChildを使うことでasync blockの中でAsync<'T>をバックグラウンド処理できるようになる

let wakeUp = async {
    do! Async.Sleep(1500)
    do stdout.WriteLine("Wake up!")
}

let goodMorning = async { stdout.WriteLine("goodMorning") }
let iamSleep    = async { stdout.WriteLine("zzz...") }

async { 
    let! (iamWakeUp:Async<unit>) = Async.StartChild( wakeUp, 100 )
    try
        do! iamWakeUp
    with :? exn ->
        do! iamSleep 
} |> Async.RunSynchronously
// world hello
let hello = async {
    do! Async.Sleep(100)
    do stdout.WriteLine("hello") }

let world = async { do stdout.WriteLine("world") }

async {
    let! child = hello |> Async.StartChild
    do! world
    do! child
} |> Async.RunSynchronously

.

Taskを使った例 .

AwaitIAsyncResultを使うことで待機させることができる

.

無期限に待つ例

let apple  = async { return 100 }
let banana = async { return 70  }
let cherry = async { return 350 }
let sum = [ apple; banana; cherry ]

let eating = async { do stdout.WriteLine("Taste good!") }

async {
    let! (withinMoney:bool) = Async.AwaitIAsyncResult( sum |> Async.Parallel |> Async.StartAsTask)
    do!  eating
} |> Async.RunSynchronously

タイムアウトを指定した例

let wakeUp = async {
    do! Async.Sleep(1500)
    return stdout.WriteLineAsync("Wake up!")
}

let goodMorning = async { stdout.WriteLine("goodMorning") }
let iamSleep = async { stdout.WriteLine("zzz...") }

async {
    let! (wakeUpWithinTime:bool) = Async.AwaitIAsyncResult( wakeUp |> Async.StartAsTask ,100 )
    if    wakeUpWithinTime
    then  do! goodMorning
    else  do! iamSleep
} |> Async.RunSynchronously

5. Exception and Cancel

let green  = fun _ ->  stdout.WriteLine("green") 
let yellow = fun _ ->  stdout.WriteLine("yellow") 
let red    = fun _ ->  stdout.WriteLine("red") 

// 通常の動作
let signalGreen = async { do () }
Async.StartWithContinuations ( signalGreen, green, yellow, red )

// エラー処理
let signalYellow:Async<obj> = async {
    return raise <| new System.Exception()
}
Async.StartWithContinuations ( signalYellow, green, yellow, red )

// キャンセル処理
let signalRed (tokenSource:System.Threading.CancellationTokenSource)  = async {
    do! Async.Sleep(1000)
}

let tokenSource = new System.Threading.CancellationTokenSource()
Async.StartWithContinuations ( signalRed tokenSource , green, yellow, red , tokenSource.Token )
tokenSource.Cancel()
Remove all ads