繁体   English   中英

F#中的异步计算

[英]Asynchronous computation in F#

clientSystem.Net.Http.HttpClient的实例。 在下面的代码中

var response = await client.PostAsync(url, content);
processResponse(response);

在第一行和第二行代码之间没有线程块,因此,如果我们在U​​I线程中,则UI在POST往返期间保持响应。

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

let response = client.PostAsync(url, content) |> Async.AwaitTask |> Async.RunSynchronously
processResponse(response)

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

编辑

也许更多的上下文会有所帮助。

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

可能的C#应用​​程序解决方案

F#库:

let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    } |> Async.StartAsTask

C#应用点击处理程序

private async void button1_Click(object sender, EventArgs e) {
    var s = await FSLongWork();
    label1.Text = s;
}

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

this.button1.Click += new System.EventHandler(this.button1_Click);

可能的F#应用程序解决方案

F#库:

let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    }

F#应用点击处理程序

let button1_Click (sender : obj) e = 
    async {
        let! s = FSLongWork()
        label1.Text <- s
    }

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

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并使用难看的Microsoft.FSharp.Control.FSharpAsync.StartAsTask(FSLongWork(), null, null); 在C#应用中

另一方面,第一个实现(使用Async.StartAsTask )导致在C#中更自然的使用(只需await FSLongWork() ),但是当F#应用程序使用时意味着async-> Task->异步往返

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

参见此处: https : //docs.microsoft.com/zh-cn/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async

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

因此,在这种情况下:

async {
  let! response = client.PostAsync(url, content) |> Async.AwaitTask
  processResponse response
} |> Async.Start

在良好的集成方面,我希望能够做到以下几点:

F#库:

let FSLongWork() = 
    async {
        do! Async.Sleep(5000);
        return "F#"
    }

C#应用点击处理程序

private async void button1_Click(object sender, EventArgs e) {
    var s = await FSLongWork();
    label1.Text = s;
}

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

可能对将来的功能请求很重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM