LoginSignup
4
1

More than 5 years have passed since last update.

Summary

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

0. Prepare

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

let!とかdo!とかのbang!Asyncをはぎとる。つまりAsync<'T>'Tに、Async>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()
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1