dotNet中是否存在DirectoryInfo.GetFiles/Directory.GetDirectories的异步版本?我想在F#异步块中使用它们,并且拥有一个可以使用AsyncCallbacks调用的版本会很好.
问题是我试图吮吸一堆目录,可能是在慢速网络连接上的SMB挂载上,我不希望一堆线程池线程在等待网络读取时可能正在做其他工作.
什么是F#的异步工作流的Scala等价物?
例如,如何跟随F#snippet转换为惯用的Scala?
open System.Net
open Microsoft.FSharp.Control.WebExtensions
let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
"MSDN", "http://msdn.microsoft.com/"
"Bing", "http://www.bing.com"
]
let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
printfn "Read %d characters for %s" html.Length name
with
| ex -> printfn "%s" (ex.Message);
}
let runAll() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
runAll()
Run Code Online (Sandbox Code Playgroud) 我想测试以下异步工作流程(使用NUnit + FsUnit):
let foo = async {
failwith "oops"
return 42
}
Run Code Online (Sandbox Code Playgroud)
我为它编写了以下测试:
let [<Test>] TestFoo () =
foo
|> Async.RunSynchronously
|> should equal 42
Run Code Online (Sandbox Code Playgroud)
自从foo抛出后,我在单元测试运行器中得到以下stacktrace:
System.Exception : oops
at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously(CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
at ExplorationTests.TestFoo() in ExplorationTests.fs: line 76
Run Code Online (Sandbox Code Playgroud)
不幸的是,堆栈跟踪并没有告诉我异常的位置.它在RunSynchronously处停止.
某处我听说Async.Catch神奇地恢复了堆栈跟踪,所以我调整了我的测试:
let [<Test>] TestFooWithBetterStacktrace () =
foo
|> Async.Catch
|> Async.RunSynchronously
|> fun x -> match x with
| Choice1Of2 x -> x |> should equal 42
| Choice2Of2 …Run Code Online (Sandbox Code Playgroud) 让我们说我想刮一个网页,并提取一些数据.我最有可能写这样的东西:
let getAllHyperlinks(url:string) =
async { let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
use stream = rsp.GetResponseStream() // depends on rsp
use reader = new System.IO.StreamReader(stream) // depends on stream
let! data = reader.AsyncReadToEnd() // depends on reader
return extractAllUrls(data) } // depends on data
Run Code Online (Sandbox Code Playgroud)
的let!讲述F#在另一个线程来执行代码,然后将结果结合到一个变量,并继续处理.上面的示例使用两个let语句:一个用于获取响应,一个用于读取所有数据,因此它至少生成两个线程(如果我错了,请纠正我).
虽然上面的工作流程会产生多个线程,但执行顺序是串行的,因为工作流程中的每个项目都依赖于前一个项目.在其他线程返回之前,无法在工作流程中进一步评估任何项目.
let!在上面的代码中有多个有什么好处?
如果没有,该代码如何更改以利用多个let!语句?
我正在尝试向URL发出异步Web请求,如果请求耗时太长,将返回该URL.我正在使用F#异步工作流和System.Net.Http库来执行此操作.
但是,我无法捕获async工作流中System.Net.Http库引发的Task/OperationCancelledExceptions .相反,异常是在Async.RunSynchronously方法中引发的,如此堆栈跟踪中所示:
> System.OperationCanceledException: The operation was canceled. at
> Microsoft.FSharp.Control.AsyncBuilderImpl.commit[a](Result`1 res)
> at
> Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously[a](CancellationToken
> token, FSharpAsync`1 computation, FSharpOption`1 timeout) at
> Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1
> computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
> at <StartupCode$FSI_0004>.$FSI_0004.main@()
Run Code Online (Sandbox Code Playgroud)
代码:
#r "System.Net.Http"
open System.Net.Http
open System
let readGoogle () = async {
try
let request = new HttpRequestMessage(HttpMethod.Get, "https://google.co.uk")
let client = new HttpClient()
client.Timeout <- TimeSpan.FromSeconds(0.01) //intentionally low to always fail in this example
let! response = client.SendAsync(request, HttpCompletionOption.ResponseContentRead) |> Async.AwaitTask …Run Code Online (Sandbox Code Playgroud) f# async-workflow task-parallel-library computation-expression
我正在使用一个用C#编写的库,并使用async / await模式。在C#中,我可以用调用它来等待某些东西,ConfigureAwait(false)但是当我从F#使用库时,我看不到做相同事情的方法吗?
目前,我确实SomeMethodAsync() |> Async.AwaitTask将其转换为AsyncF#工作流程,但是ConfigureAwait(false)调用时我该如何与F#一样SomeMethodAsync呢?
编辑:
在F#Slack频道中提供了一些出色的帮助,并进行了一些附加的搜索,我在这里找到了关于如何切换上下文的很好的解释:http : //tomasp.net/blog/async-non-blocking-gui.aspx/
我正在尝试在F#中使用异步工作流来获取多个Web请求.
但是,我的一些请求偶尔会返回错误(例如http 500),我不知道如何处理这个问题.看起来我的F#程序在调试器中运行时陷入无限循环.
我可能错过了一些东西,因为我看到的例子没有开箱即用.我找到的第一件事就是帮助了这段代码:
type System.Net.WebRequest with
member req.GetResponseAsync() =
Async.BuildPrimitive(req.BeginGetResponse, req.EndGetResponse)
Run Code Online (Sandbox Code Playgroud)
然后我有一些代码来获取请求,这是我见过的例子中非常标准的:
let async_value = async {
let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
return (rsp :?> HttpWebResponse).StatusCode
}
Run Code Online (Sandbox Code Playgroud)
然后我试着得到结果:
let status = Async.RunSynchronously(async_value)
Run Code Online (Sandbox Code Playgroud)
但是当我在调试器中运行我的程序时,它会req.EndGetResponse因为服务器返回内部服务器错误500 而中断.如果我继续执行,它会进入一个时髦的循环,中断req.EndGetResponse(有时连续几次)和let status = Async.RunSynchronously(async_value) .
如何解决异常问题以便获取状态代码?另外,我需要上面做的类型吗?或者我错过了F#/ VS 2010 Beta 1的一些库/ dll,其中这已经是其中的一部分了?
我实际上使用Async.RunSynchronously(Async.Parallel(my_array_of_async_values))并行运行多个请求,尽管我不认为这与我遇到的异常问题有关.
事实上我遇到的例子只是使用Async.Run而不是Async.RunSynchronously可能是一个指标,我错过了一些东西...... = /
我使用Async.Catch来处理异步工作流抛出的异常:
work
|> Async.Catch
|> Async.RunSynchronously
|> fun x -> match x with
| Choice1Of2 _ -> () // success
| Choice2Of2 ex -> // failure, handle exception
Run Code Online (Sandbox Code Playgroud)
今天我注意到Async.Catch不处理OperationCanceledExceptions.而不是从Async.Catch获得选择,异常不断冒泡直到它击中我.我希望下面的测试是红色的,但它是绿色的:
[<Test>]
let ``Async.Catch doesnt work on OperationCancelledExceptions``() =
use cancellationTokenSource = new System.Threading.CancellationTokenSource(1000)
let work = async {
while true do
do! Async.Sleep 100
}
(fun () -> work
|> Async.Catch
|> fun x -> Async.RunSynchronously (x, cancellationToken=cancellationTokenSource.Token)
|> ignore)
|> should throw typeof<System.OperationCanceledException>
Run Code Online (Sandbox Code Playgroud)
使用Async.Catch + Choices +匹配以及其他一些使用try/catch块评估一些异常似乎不正确......它看起来像下面这样,这太复杂了.除此之外,我想知道Async.Catch有什么用,因为我必须使用try/catch块...:
[<Test>]
let ``evaluating …Run Code Online (Sandbox Code Playgroud) 您总是听说功能代码本质上比非功能代码更容易并行化,因此我决定编写一个执行以下操作的函数:
给定字符串输入,总计每个字符串的唯一字符数.因此,给定输入[ "aaaaa"; "bbb"; "ccccccc"; "abbbc" ],我们的方法将返回a: 6; b: 6; c: 8.
这是我写的:
(* seq<#seq<char>> -> Map<char,int> *)
let wordFrequency input =
input
|> Seq.fold (fun acc text ->
(* This inner loop can be processed on its own thread *)
text
|> Seq.choose (fun char -> if Char.IsLetter char then Some(char) else None)
|> Seq.fold (fun (acc : Map<_,_>) item ->
match acc.TryFind(item) with
| Some(count) -> acc.Add(item, count + 1)
| None -> acc.Add(item, …Run Code Online (Sandbox Code Playgroud) 我正在尝试理解F#中的异步工作流程,但我发现有一部分我真的不明白,希望有人可以帮助我.
以下代码工作正常:
let asynWorkflow = async{
let! result = Stream.TryOpenAsync(partition) |> Async.AwaitTask
return result
}
let stream = Async.RunSynchronously asynWorkflow
|> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition)
Run Code Online (Sandbox Code Playgroud)
我定义了一个异步工作流,其中TryOpenAsync返回一个Task类型.我用Async.AwaitTask将它转换为Async.(副任务:"等待"任务?它不等待它只是转换它,是吗?我认为它与Task.Wait或await关键字无关).让我"等待"它!并返回它.要启动工作流,我使用RunSynchronously,它应该启动工作流并返回结果(绑定它).在结果上,我检查是否找不到流.
但现在是我的第一个问题.为什么我必须在另一个异步计算中包装TryOpenAsync调用并让它!("等待")吗?例如,以下代码不起作用:
let asynWorkflow = Stream.TryOpenAsync(partition) |> Async.AwaitTask
let stream = Async.RunSynchronously asynWorkflow
|> fun openResult -> if openResult.Found then openResult.Stream else Stream(partition)
Run Code Online (Sandbox Code Playgroud)
我认为AwaitTask使它成为Async和RunSynchronously应该启动它.然后使用结果.我错过了什么?
我的第二个问题是为什么有"Async.Let!" 功能可用?也许是因为它不起作用或更好,为什么它不适用于以下代码?
let ``let!`` task = async{
let! result = task |> Async.AwaitTask
return result
}
let stream = Async.RunSynchronously ( ``let!`` (Stream.TryOpenAsync(partition)) )
|> fun …Run Code Online (Sandbox Code Playgroud) async-workflow ×10
f# ×10
asynchronous ×4
.net ×1
async-await ×1
c# ×1
let ×1
nunit ×1
scala ×1
unit-testing ×1