我有一组 F# 脚本,它们调用我们创建的各种库,其中许多库公开了最初用 C# 编写的异步方法。最近我发现脚本停止工作了(我想距离我上次使用它们已经有半年了,当时它们还可以工作)。
我试图隔离问题并提出了以下代码来重现它:
首先,我们考虑一个包含以下 C# 类的库:
public class AsyncClass
{
public async Task<string> GetStringAsync()
{
var uri = new Uri("https://www.google.com");
var client = new HttpClient();
var response = await client.GetAsync(uri);
var body = await response.Content.ReadAsStringAsync();
return body;
}
}
接下来,我们使用以下代码从 F#(FSX 脚本)调用该库:
let asyncClient = AsyncClass()
let strval1 = asyncClient.GetStringAsync() |> Async.AwaitTask |> Async.RunSynchronously
printfn "%s" strval1
let strval2 =
async {
return! asyncClient.GetStringAsync() |> Async.AwaitTask
} |> Async.RunSynchronously
printfn "%s" strval2
获取strval1
最终陷入僵局,而strval2
检索得很好(我很确定第一个场景在几个月前也可以工作,所以看起来某种更新可能导致了这种情况)。
这很可能是同步上下文问题,其中线程基本上“等待自身完成”,但我不明白第一次调用到底出了什么问题 - 我看不出它有什么问题。
StackOverflow 上的类似问题:
-
为什么我必须将 Async 包装到另一个异步工作流程中并让!它? https://stackoverflow.com/questions/47330249/why-do-i-have-to-wrap-an-asynct-into-another-async-workflow-and-let-it- 这似乎是同一个问题,但没有给出足够的信息,并且缺少一个简单的重现示例
-
为什么 Async.RunSynchronously 挂起? https://stackoverflow.com/questions/52229404/why-is-async-runsynchronously-hanging- 这很相似,但作者犯了一个明显的错误
所以一个.netTask
将立即开始,而 F#async {}
很懒。因此,当您将任务包装在async { }
它变得懒惰,因此将具有以下特征:Async.RunSynchronously
正在期待。
一般来说,我仅在执行 f# 异步操作时使用 async {},如果我正在使用 .net 任务,我将使用任务生成器.fs https://github.com/rspeele/TaskBuilder.fs(在 nuget 中可用)。是比较了解的Task
诸如此类的特质ConfigureAwait(continueOnCapturedContext: false)
.
open FSharp.Control.Tasks.V2.ContextInsensitive
task {
let! x = asyncClient.GetStringAsync()
//do something with x
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)