gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 15:12:54 25 4
gpt4 key购买 nike

用于说明 F# 中异步工作流的一个常见示例是并行检索多个网页。一个这样的例子在:http://en.wikibooks.org/wiki/F_Sharp_Programming/Async_Workflows此处显示的代码以防将来链接更改:

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并行运行多个操作但操作本身不是异步实现的,因此这不会避免阻塞线程池中过多的线程。

异步。 为了使代码完全异步,downloaddownloadAndExtractLinks函数也应该是异步的,这样你就可以使用 AsyncDownloadStringWebClient :

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 }

然后您可以更改 main 函数以构建一个重试下载 10 次的工作流:
let testAsynchronous() = 
pmap (asyncRetry 10 downloadAndExtractLinks) urls

共享状态。 另一个问题是 Async.Parallel只有在所有下载完成后才会返回(如果有一个错误的网站,您将不得不等待)。如果您想在结果返回时显示结果,您将需要更复杂的东西。

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

我写了一个 MSDN series about agents还有 two articles适用于具有大量 F# 代理代码示例的 developerFusion。

关于f# - F# 中的全局状态和异步工作流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15857807/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com