运行 f# 工作流中的 c# 异步方法
Running c# async method in f# workflow
我试图让下面的代码在 F# 异步工作流中工作,但我收到错误 "Unexpected symbol '}' in expression"。一般来说,我对 F# 和异步都比较陌生。我在这里错过了什么。
let someFunction (req : HttpRequestMesssage) a b =
// code
async{
let! readToProvider =
req.Content.ReadAsMultipartAsync(provider)
|> Async.AwaitIAsyncResult
} |> Async.RunSynchronously
req.CreateResponse(HttpStatusCode.OK)
你做得对。您收到错误只是因为您使用 let!
表达式结束 async
块。将其更改为 return!
或 do! ... |> Async.Ignore
即可。
F# 中的块(既不是工作流也不是常规代码块)不应以 let
.
结尾
当然,如果所有你真的在工作流程中做的是一个调用,您根本不需要工作流块(您永远不需要为单个调用编写块)。就这样
req.Content.ReadAsMultipartAsync provider
|> Async.AwaitIAsyncResult
|> Async.Ignore
|> Async.RunSynchronously
req.CreateResponse HttpStatusCode.OK
或者就此而言,只需使用内置的 Tasks Wait,它的作用与 Async.RunSynchronously:
(req.Content.ReadAsMultipartAsync provider).Wait()
我担心我之前的回答不是你想要的。我提供的只是帮助您解决了编译错误。但关于它的一件事是,它 not 运行 是异步的。 Task.Wait
和 Async.RunSynchronously
都会阻塞 运行ning 线程,直到操作完成。
如果你真的想 是 异步的,即不阻塞,你必须把整个方法,或者至少是它的最后一部分,放到 async
块,这样你实际上是在向调用者返回一个 async
操作。所以答案是
let someFunction (req : HttpRequestMesssage) a b =
async {
let! readToProvider = (req.Content.ReadAsMultipartAsync provider) |> Async.AwaitIAsyncResult
return req.CreateResponse HttpStatusCode.OK
}
这个选项returns不是响应,而是Async<Response>
。所以现在 caller 可以决定如何 运行 它,阻塞或真正异步。
这样,如果您使用处理异步请求的网络服务器,那么您可以简单地将此函数连接到端点(可能在点将 Async
转换为 Task
连接,因为大多数 .net 异步 Web 服务器都是从 C# 角度编写的)并且它将 运行 异步而不阻塞线程。或者,如果您从另一个异步操作调用它,您可以执行 do! someFunction ...
并且它会 运行 异步。但如果调用者不关心,只想同步 运行,它可以做 someFunction ... |> Async.RunSynchronously
。所以你在那里可以获得更大的灵活性。如果这是更常见的用例,您始终可以定义 let someFunctionSync ... = someFunction ... |> Async.RunSynchronously
。
除非你真的想强制阻止,否则我建议你这样做。
我试图让下面的代码在 F# 异步工作流中工作,但我收到错误 "Unexpected symbol '}' in expression"。一般来说,我对 F# 和异步都比较陌生。我在这里错过了什么。
let someFunction (req : HttpRequestMesssage) a b =
// code
async{
let! readToProvider =
req.Content.ReadAsMultipartAsync(provider)
|> Async.AwaitIAsyncResult
} |> Async.RunSynchronously
req.CreateResponse(HttpStatusCode.OK)
你做得对。您收到错误只是因为您使用 let!
表达式结束 async
块。将其更改为 return!
或 do! ... |> Async.Ignore
即可。
F# 中的块(既不是工作流也不是常规代码块)不应以 let
.
当然,如果所有你真的在工作流程中做的是一个调用,您根本不需要工作流块(您永远不需要为单个调用编写块)。就这样
req.Content.ReadAsMultipartAsync provider
|> Async.AwaitIAsyncResult
|> Async.Ignore
|> Async.RunSynchronously
req.CreateResponse HttpStatusCode.OK
或者就此而言,只需使用内置的 Tasks Wait,它的作用与 Async.RunSynchronously:
(req.Content.ReadAsMultipartAsync provider).Wait()
我担心我之前的回答不是你想要的。我提供的只是帮助您解决了编译错误。但关于它的一件事是,它 not 运行 是异步的。 Task.Wait
和 Async.RunSynchronously
都会阻塞 运行ning 线程,直到操作完成。
如果你真的想 是 异步的,即不阻塞,你必须把整个方法,或者至少是它的最后一部分,放到 async
块,这样你实际上是在向调用者返回一个 async
操作。所以答案是
let someFunction (req : HttpRequestMesssage) a b =
async {
let! readToProvider = (req.Content.ReadAsMultipartAsync provider) |> Async.AwaitIAsyncResult
return req.CreateResponse HttpStatusCode.OK
}
这个选项returns不是响应,而是Async<Response>
。所以现在 caller 可以决定如何 运行 它,阻塞或真正异步。
这样,如果您使用处理异步请求的网络服务器,那么您可以简单地将此函数连接到端点(可能在点将 Async
转换为 Task
连接,因为大多数 .net 异步 Web 服务器都是从 C# 角度编写的)并且它将 运行 异步而不阻塞线程。或者,如果您从另一个异步操作调用它,您可以执行 do! someFunction ...
并且它会 运行 异步。但如果调用者不关心,只想同步 运行,它可以做 someFunction ... |> Async.RunSynchronously
。所以你在那里可以获得更大的灵活性。如果这是更常见的用例,您始终可以定义 let someFunctionSync ... = someFunction ... |> Async.RunSynchronously
。
除非你真的想强制阻止,否则我建议你这样做。