首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F#中的异步计算

F#中的异步计算
EN

Stack Overflow用户
提问于 2018-02-23 09:10:07
回答 2查看 777关注 0票数 2

让客户端成为System.Net.Http.HttpClient的一个实例。在以下代码中

代码语言:javascript
复制
var response = await client.PostAsync(url, content);
processResponse(response);

在第一行代码和第二行代码之间没有线程块,所以如果我们在UI线程中,UI在后往返过程中保持响应。

获得相同的非阻塞行为的F#代码是什么?是

代码语言:javascript
复制
let response = client.PostAsync(url, content) |> Async.AwaitTask |> Async.RunSynchronously
processResponse(response)

正确的密码?我还不清楚RunSynchronously是否阻塞了当前线程。如果是这样,我们如何获得与等待相同的非阻塞行为?

编辑

也许更多的背景会有帮助。

我有一个包含两个项目的Visual解决方案:一个WPF/WinForms应用程序和一个由应用程序引用的F#库。库提供一个名为FSLongWork()的函数/方法,它执行长I/O操作,例如使用HttpClient.GetAsync/PostAsync向远程服务器发送HTTP或POST,并返回一个字符串。应用程序前端是一个带有按钮和标签的简单窗口。按钮单击处理程序必须: 1)调用F#库中的F#();2)在标签中写入依赖于步骤1中返回的字符串的内容。当然,步骤1必须异步进行,以保持UI响应能力。

可能的C#应用解决方案

F#库:

代码语言:javascript
复制
let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    } |> Async.StartAsTask

C#应用程序单击处理程序

代码语言:javascript
复制
private async void button1_Click(object sender, EventArgs e) {
    var s = await FSLongWork();
    label1.Text = s;
}

C#应用程序按钮处理程序注册

代码语言:javascript
复制
this.button1.Click += new System.EventHandler(this.button1_Click);

可能的F#应用解决方案

F#库:

代码语言:javascript
复制
let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    }

F#应用程序单击处理程序

代码语言:javascript
复制
let button1_Click (sender : obj) e = 
    async {
        let! s = FSLongWork()
        label1.Text <- s
    }

F#应用程序按钮处理程序注册

代码语言:javascript
复制
button1.Click.Add(RoutedEventHandler(fun sender e -> button1_Click sender e |> Async.StartImmediate)

我看到的问题是,F#库函数(FSLongWork)在这两种解决方案中是不同的(|> Async.StartAsTask仅在第一种解决方案中),这在可重用性方面并不好。

我们可以使用F#中的第一个实现(将let! s = FSLongWork()更改为let! s = FSLongWork() |> Async.AwaitTask)。

第二个实现可以用于C# (将var s = await FSLongWork();更改为var s2 = await Microsoft.FSharp.Control.FSharpAsync.StartAsTask(FSLongWork(), null, null);)。

然而,在我看来,这有点尴尬:自然的F#实现将是第二个(没有Async.StartAsTask),但这需要引用Microsoft.FSharp和在C#应用程序中使用相当丑陋的Microsoft.FSharp.Control.FSharpAsync.StartAsTask(FSLongWork(), null, null);

另一方面,第一个实现(使用Async.StartAsTask)导致了在C#中更自然的使用(简单地说是await FSLongWork()),但是当一个F#应用程序使用时,它意味着am异步->任务->异步往返。

是否有一种方法可以编写F#库,以便C#用户不需要引用FSharp.Core,并且不影响F#函数的实现方式?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-24 07:16:16

就良好的融合而言,我希望能够做到以下几点:

F#库:

代码语言:javascript
复制
let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    }

C#应用程序单击处理程序

代码语言:javascript
复制
private async void button1_Click(object sender, EventArgs e) {
    var s = await FSLongWork();
    label1.Text = s;
}

换句话说,当我在Async<>中使用await时,Task<>和C#之间的转换是自动的/隐式的。我认为这是可能的,我无法找到方法去做,因此我提出了问题。显然,这是不可能的,并且需要一些手动转换管道(例如,在我报告的可能的解决方案中)。

也许它可以作为未来功能请求的素材。

票数 1
EN

Stack Overflow用户

发布于 2018-02-23 09:25:33

见此处:https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async

  1. Async.RunSynchronously将在另一个线程上启动异步工作流,并等待其结果。
  2. Async.Start将在另一个线程上启动异步工作流,不会等待其结果。

所以在这种情况下:

代码语言:javascript
复制
async {
  let! response = client.PostAsync(url, content) |> Async.AwaitTask
  processResponse response
} |> Async.Start
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48944486

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档