【问题标题】:Rewriting C# code using Task.WhenAll in F#在 F# 中使用 Task.WhenAll 重写 C# 代码
【发布时间】:2015-11-01 06:57:38
【问题描述】:

我有如下接口方法:

Task<string[]> GetBlobsFromContainer(string containerName);

及其在 C# 中的实现:

var container = await _containerClient.GetContainer(containerName);
var tasks = container.ListBlobs()
                     .Cast<CloudBlockBlob>()
                     .Select(b => b.DownloadTextAsync());
return await Task.WhenAll(tasks);

当我尝试在 F# 中重写它时:

member this.GetBlobsFromContainer(containerName : string) : Task<string[]> =
    let task = async {
        let! container = containerClient.GetContainer(containerName) |> Async.AwaitTask
        return container.ListBlobs()
               |> Seq.cast<CloudBlockBlob>
               |> Seq.map (fun b -> b.DownloadTextAsync())
               |> ??
    }
    task |> ??

我被最后几行卡住了。

如何正确从F#返回Task&lt;string[]&gt;

【问题讨论】:

    标签: f# async-await task-parallel-library c#-to-f#


    【解决方案1】:

    我不得不猜测containerClient 的类型是什么,我找到的最接近的是CloudBlobClient(它没有getContainer: string -&gt; Task&lt;CloubBlobContainer&gt;,但应该不难适应)。然后,您的函数可能如下所示:

    open System
    open System.Threading.Tasks
    open Microsoft.WindowsAzure.Storage.Blob
    open Microsoft.WindowsAzure.Storage
    
    let containerClient : CloudBlobClient = null
    
    let GetBlobsFromContainer(containerName : string) : Task<string[]> =
        async {
            let container = containerClient.GetContainerReference(containerName)
            return! container.ListBlobs()
                   |> Seq.cast<CloudBlockBlob>
                   |> Seq.map (fun b -> b.DownloadTextAsync() |> Async.AwaitTask)
                   |> Async.Parallel
        } |> Async.StartAsTask
    

    我将返回类型更改为Task&lt;string[]&gt; 而不是Task&lt;string seq&gt;,因为我想您想保留接口。否则,我建议去掉 Task 并在 F#-only 代码中使用 Async

    【讨论】:

    • 抱歉,无法描述containerClient.GetContainerReference。它是 Azure SDK 中 CloudStorageAccount 之上的抽象。是的,你是对的,实际的返回类型是Task&lt;string[]&gt;。以前是Task&lt;IEnumerable&lt;string&gt;&gt;,但我已经改变了。
    • 我不知道的是Async.Parallel,完全忘记了return!
    【解决方案2】:

    这行得通吗?

    member this.GetBlobsFromContainer(containerName : string) : Task<string seq> =
        let aMap f x = async {
            let! a = x
            return f a }
        let task = async {
            let! container = containerClient.GetContainer(containerName) |> Async.AwaitTask
            return! container.ListBlobs()
                |> Seq.cast<CloudBlockBlob>
                |> Seq.map (fun b -> b.DownloadTextAsync() |> Async.AwaitTask)
                |> Async.Parallel
                |> aMap Array.toSeq
        }
        task |> Async.StartAsTask
    

    我不得不对containerClient 等做出一些假设,所以我无法对此进行测试,但至少它可以编译。

    【讨论】:

    • 嗨,马克,感谢您的回复!抱歉,没有描述 containerClient.GetContainerReference() 是什么。为什么这里需要一个额外的函数aMap
    • 为了将Async&lt;string []&gt;转换为Async&lt;string seq&gt;
    • 我明白了。所以如果我可以返回Task&lt;string[]&gt; 那我就不需要了吗?
    • 谢谢您,先生!希望你不介意我已经接受了代表较少的 RCH 的回答。
    • 一点也不!他或她也击败了我几秒钟:)
    猜你喜欢
    • 2010-12-08
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多