Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# F中的全局状态和异步工作流#_F# - Fatal编程技术网

F# F中的全局状态和异步工作流#

F# F中的全局状态和异步工作流#,f#,F#,F#中用于说明异步工作流的一个常见示例是并行检索多个网页。一个这样的例子如下所示:如果将来链接发生变化,代码如下所示: open System.Text.RegularExpressions open System.Net let download url = let webclient = new System.Net.WebClient() webclient.DownloadString(url : string) let extractLinks html = Reg

F#中用于说明异步工作流的一个常见示例是并行检索多个网页。一个这样的例子如下所示:如果将来链接发生变化,代码如下所示:

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 { for a in l -> async { return f a } }
    |> 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()
我想知道的是,人们应该如何处理全局状态的变化,例如网络连接的丢失?有没有一种优雅的方法可以做到这一点


在进行Async.Parallel调用之前,可以检查网络的状态,但在执行过程中状态可能会发生变化。假设我们想做的是暂停执行直到网络再次可用而不是失败,那么有没有一种功能性的方法可以做到这一点呢?

首先,这个例子有一个问题-它使用
Async.Parallel
并行运行多个操作,但操作本身并不是异步实现的,因此,这无法避免阻塞线程池中过多的线程

异步。要使代码完全异步,
download
download和extractlinks
函数也应该是异步的,这样您就可以使用
WebClient
asynchdownloadstring

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 { for a in l -> async { return! f a } }
    |> Async.Parallel
    |> Async.RunSynchronously
重试。现在,回答这个问题-没有处理网络故障等错误的内置机制,因此您需要自己实现这个逻辑。什么是正确的方法取决于你的情况。一种常见的方法是重试操作一定次数,并仅在异常未成功时(例如10次)抛出异常。您可以将其编写为接受其他异步工作流的原语:

let rec asyncRetry times op = async {
  try
    return! op
  with e ->
    if times <= 1 then return (reraise e)
    else return! asyncRetry (times - 1) op }
共享状态。另一个问题是,
Async.Parallel
只会在所有下载完成后返回(如果有一个网站出现故障,您将不得不等待)。如果您想在结果返回时显示结果,则需要更复杂的东西

一个很好的方法是使用F#agent——创建一个agent,它存储迄今为止获得的结果,并可以处理两条消息——一条用于添加新结果,另一条用于返回当前状态。然后,您可以启动多个异步任务,将结果发送给代理,并且在单独的异步工作流中,您可以使用轮询检查当前状态(例如,更新用户界面)


我为developerFusion写了一篇文章,其中有大量关于F#代理的代码示例。

Tom,虽然我非常喜欢F#代理,但我不明白这是如何像Haskell那样的函数式编程。它所做的似乎是将状态(Haskell中的IO单子)视为要传递给函数的东西,它将状态视为要由多个代理“同时”变异并通过代理之间的消息传递进行仲裁的东西。使用代理绝对不是Haskell那样的函数式编程。老实说,我并不认为这个问题的纯功能解决方案是那么优雅和有用。消息传递并发只是F#中可用的另一个有用的范例,我认为它对于需要协调的并发进程非常有效。这是我目前正在努力解决的问题。通过Haskell等人发现了FP(但仍然非常缺乏经验),诱惑是在F#中也采用完全纯粹的方法。我认为,找到正确的范例组合将是一个漫长的学习过程。
let testAsynchronous() = 
  pmap (asyncRetry 10 downloadAndExtractLinks) urls