C#:如何在 F# 中实现为 "async"和 "!"?

标签 c# asynchronous f# callback aop

最近阅读 F#,我发现“async”和“!” (砰!:p)是非常有用的功能。 (题外话,这是一个例子,表明编程语言不仅是一个学术研究课题,而且是一个现实生活中的生产力设计课题)。

以下是 Luca Bolognese 在 PDC 2008 上的演讲:

let internal loadPrices ticker = async {
    let url = "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=9&e=30&f=2008&g=d&a=2&b=13&c=1986&ignore=.csv"
    let req = WebRequest.Create(url)
    let! resp = req.AsyncGetResponse() //athos: need F# Powerpack

    let stream = resp.GetResponseStream()
    let reader = new StreamReader(stream)
    let! csv = reader.AsyncReadToEnd()

    let prices =
        csv.Split([|'\n'|])
        |> Seq.skip 1
        |> Seq.map (fun line -> line.Split([|','|]))
        |> Seq.filter (fun values -> values |> Seq.length = 7)
        |> Seq.map (fun values ->
        System.DateTime.Parse(values.[0]),
        float values.[6])    

    return prices }

迷人的部分是,回调处理得很好:程序员不需要处理 BackgroundWorker 或 Theads 的 Join()。

那么,在 C# 中,是否有一个优雅的解决方案来实现 F#“aync”和“!”特征? 例如,是否可以像下面那样或以类似的轻松方式执行“异步...运行...回调”?

public void GetApplicationSettings()
{ 
    async(objAsyncRunner = new System.Async.Runner() ) //similar to "using" in C#
    run // similar to "if" in C#
    {
        string url = "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=9&e=30&f=2008&g=d&a=2&b=13&c=1986&ignore=.csv"
        var req = WebRequest.Create(url);
        var resp = req.AsyncGetResponse();
    }
    callback run // similar to "if else" in C#
    {
        var stream = resp.GetResponseStream();
        var reader = new StreamReader(stream);
        var csv = reader.AsyncReadToEnd();
    }
    callback // similar to "else" in C#
    {
        var prices = csv.Split('\n').....;
    }
}

附言。我知道你们中的一些人会说:athos,只需使用 F#! 是的...我不反对 F# 但它需要时间来改变整个部门,在此之前我希望能从 F# 那里借鉴一些优点。

我知道有一些方面编程概念可以扩展 C# 功能。然而,它仍然没有达到 F# 级别。

例如,我可以从 http://www.sharpcrafters.com 扩展 PostSharp ,因此通过简单地为方法分配一个属性,强制它在专用线程中异步运行:

[RunInADedicatedThread(Async = true)]
public void GetApplicationSettings()
{ ... }

如果属性已准备好:

[Serializable]
[AttributeUsage( AttributeTargets.Method | AttributeTargets.Class )]
[MulticastAttributeUsage( MulticastTargets.Method )]
public sealed class RunInADedicatedThreadAttribute : MethodInterceptionAspect
// MethodInterceptionAspect is extending PostSharp
{
    public bool Async { get; set; }

    public override void OnInvoke( MethodInterceptionArgs args )
    {
        if (Async)
        {
            //MyThreadPool is my extention for PostSharp 
            MyThreadPool.GetThread().ExecuteAsync(
                () =>
                    {
                        args.Proceed();
                    } );
            return;
        }
        MyThreadPool.GetThread().Execute( args.Proceed );
    }
}

这有点帮助,但仍然不是 F# 级别:

  • the "run in a dedicated thread, asynchronously" requests are not defined on the calling, but on the method GetApplicationSettings() itself! This method might as well be renamed to GetApplicationSettingsAsynchronously(), isn't it;
  • also, this can't help the callback part;
  • let alone the F# "async" feature to use less threads ... i can even drop this "advaced" feature for now...

最佳答案

正如 Brian 已经提到的,Visual Studio Async CTP是你要找的。它将异步工作流之类的东西添加到 C# 的 future 版本中。它添加了类似于 F# 中的异步工作流async 方法和行为类似于 let!await 关键字。两者之间存在一些差异,我写了一个 series of articles that compares them .

不幸的是,C# 中的异步支持仍然是 CTP。如果您想编写生产质量的异步代码,最好的选择是用 F# 编写并使用 Tasks 从 C# 中引用它。这SO question discusses how to do that .

您可以通过多种方式在 C# 中模拟类似 async 的东西。 Brian 提到了使用 LINQ(在他的博客文章中),但这非常有限。我认为使用迭代器更灵活。这是来自 article that does exactly that 的示例:

static IEnumerable<IAsync> DownloadAsync(string url)
{
  WebRequest req = HttpWebRequest.Create(url);
  Async<WebResponse> response = req.GetResponseAsync();
  yield return response;

  Stream resp = response.Result.GetResponseStream();
  Async<string> html = resp.ReadToEndAsync().ExecuteAsync<string>();
  yield return html;

  Console.WriteLine(html.Result);
}

这与 异步工作流 的工作方式类似,因为 C# 迭代器也被编译为状态机。杰弗里里希特的 AsyncEnumerator implements a more complete API基于这个想法。

关于C#:如何在 F# 中实现为 "async"和 "!"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6893998/

相关文章:

javascript - 如何从异步调用返回响应?

visual-studio-2015 - 如何在 F# 中优雅地操作这个 Deedle.Frame

c# - 有没有比 System.Byte.Parse ("0xAA"更好的东西来获得 F# 和 C# 上的单个字节?

visual-studio - 刚刚安装了 Visual Studio 的 v16.8.3,我似乎正在获取 F# 的标签

c# - 使用 C# 将单元格地址更改为 Excel 工作表中的行、列

c# - Entity Framework 和面向服务的架构如何入手?

c# - 异步数据和WCF?

c# - 异步调用2个方法

c# - Entity Framework 中多对多关系中的多个实体

c# - 如何获取 iOS/Android 上的当前设备语言?