簡體   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