Global state and Async Workflows in F# -
a common example used illustrate asynchronous workflows in f# retrieving multiple webpages in parallel. 1 such example given at: http://en.wikibooks.org/wiki/f_sharp_programming/async_workflows code shown here in case link changes in future:
open system.text.regularexpressions open system.net let download url = let webclient = new system.net.webclient() webclient.downloadstring(url : string) let extractlinks html = regex.matches(html, @"http://\s+") let downloadandextractlinks url = let links = (url |> download |> extractlinks) url, links.count let urls = [@"http://www.craigslist.com/"; @"http://www.msn.com/"; @"http://en.wikibooks.org/wiki/main_page"; @"http://www.wordpress.com/"; @"http://news.google.com/";] let pmap f l = seq { in l -> async { return f } } |> async.parallel |> async.run let testsynchronous() = list.map downloadandextractlinks urls let testasynchronous() = pmap downloadandextractlinks urls let time msg f = let stopwatch = system.diagnostics.stopwatch.startnew() let temp = f() stopwatch.stop() printfn "(%f ms) %s: %a" stopwatch.elapsed.totalmilliseconds msg temp let main() = printfn "start..." time "synchronous" testsynchronous time "asynchronous" testasynchronous printfn "done." main() what know how 1 should handle changes in global state such loss of network connection? there elegant way this?
one check state of network prior making async.parallel call, state change during execution. assuming 1 wanted pause execution until network available again rather fail, there functional way this?
first of all, there 1 issue example - uses async.parallel run multiple operations in parallel operations not implemented asynchronous, not avoid blocking excessive number of threads in thread pool.
asynchronous. make code asynchronous, download , downloadandextractlinks functions should asynchronous too, can use asyncdownloadstring of webclient:
let asyncdownload url = async { let webclient = new system.net.webclient() return! webclient.asyncdownloadstring(system.uri(url : string)) } let asyncdownloadandextractlinks url = async { let! html = asyncdownload url let links = extractlinks html return url, links.count } let pmap f l = seq { in l -> async { return! f } } |> async.parallel |> async.runsynchronously retrying. now, answer question - there no built-in mechanism handling of errors such network failure, need implement logic yourself. right approach depends on situation. 1 common approach retry operation number of times , throw exception if not succeed e.g. 10 times. can write primitive takes other asynchronous workflow:
let rec asyncretry times op = async { try return! op e -> if times <= 1 return (reraise e) else return! asyncretry (times - 1) op } then can change main function build workflow retries download 10 times:
let testasynchronous() = pmap (asyncretry 10 downloadandextractlinks) urls shared state. problem async.parallel return once downloads have completed (if there 1 faulty web site, have wait). if want show results come back, need more sophisticated.
one nice way use f# agent - create agent stores results obtained far , can handle 2 messages - 1 adds new result , returns current state. can start multiple async tasks send result agent and, in separate async workflow, can use polling check current status (and e.g. update user interface).
i wrote msdn series agents , two articles developerfusion have plenty of code samples f# agents.
Comments
Post a Comment