PDC 2010:C#与Visual Basic的未来(中)

标签: 技术尝鲜 培训演讲 翻译引进 | 发表时间:2010-11-01 16:26 | 作者:老赵 Mikel
出处:http://blog.zhaojie.me/

前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说,谈论了未来C#和VB中最为重要的两个特性:“异步(Async)”及“编译器即服务(Compiler as a Service)”。我现在对这场演讲进行总结,但不会像上次《编程语言的发展趋势及未来方向》那样逐句翻译,而是以Anders的角度使用一种简捷合适的方式表述其完整内容。上一篇Anders讲述了async和await的使用方式,而这篇则是对这两个关键字的实现及效果作更进一步的解释。

异步方法的目标,是为了让代码与同步方法保持一致。微软要让代码充斥着回调函数,混乱不堪,它们完全不是逻辑上你想做的事情。可能您的代码中包含着一个核心模型,你也已经实现了,只是您现在想把它的执行过程变得异步化。您自己就可以享受到这一点。

与我们之前做的一些扩展一样,工作分为语言和框架两部分。语言的异步功能基于框架中的Task<T>,我们会围绕着Task<T>扩展框架,将它作为异步模型的核心。事实上,从Begin/End,或是基于事件的异步模型进行扩展往往只需要一两行封装的代码,于是您也可以得到自己的Task<T>模型。

而在语言方面,我们添加了两个新的关键字。一个是async关键字,用于把方法标记为异步。还有一个是await方法,用于等待异步工作完成,或者说是把控制权交换给调用方继续执行其他工作。这两个功能在C#和VB种均有体现。

那么什么是Task<T>呢?它表现的是一个“后续会继续进行的操作”,这可以是许多东西,Task<T>并不做任何限制,例如是一个异步I/O,后台工作线程等等,甚至可以是UI上的一个按钮,在用户点击之后任务就结束了。

Task<T>的优势在于,它使用一个对象封装了整个概念,您可以查询其结果或是状态,或是这个任务所引发的异常。您可以用它来构造一个可组合的异步模型,这正式我们目前的异步编程模型所不足的地方。

此外,它还提供了一个可组合的回调模型,您可以对一个任务指定说,在它结束之后执行另外一段代码,然后还可以对这个新的任务继续进行设定。这便构造出一个完整的逻辑流,框架会自行帮你完成这些工作。事实上await操作符便会自动把您的逻辑改写成这样的代码,它将您从Lambda表达式及回调函数中的逻辑里解放了出来,一切都交给编译器去做了。您可能会有些疑惑,不过其实这些都是编译器所擅长的事情。

由于我们统一了异步模型,我们就可以在此之上构建组合工具。例如WhenAll,它接受一系列的Task对象,并在全部结束之后返回所有结果。还有WhenAny,则等待第一个完成的任务,返回其结果。我们还有Delay,可以等待一段时间,但不占用任何资源。

沿着这个过程走一遍可能就会清晰一些。这里有个例子,一个异步方法调用另一个异步方法。我们假设这是在UI线程上执行的,消息会一个一个发送至UI线程上。

好,有人调用了DoWorkAsync,于是出现了一些任务。

DoWorkAsync的第一件事,是调用了ProcessFeedAsync。

ProcessFeedAsync方法是一个异步方法,所以它做的第一件事是构造一个表示任务的Task对象。

然后它调用了DownloadFeedAsync,这会创建另一个Task对象。然后,我们遇上了await操作符,这意味着ProcessFeedAsync后面的部分,将作为DownloadFeedAsync完成后的回调函数/continuation里的工作。

于是任务返回至DoWorkAsync,我们得到了t1这个对象。

同样的过程会再次出现,是为t2。

然后便调用了Task.WhenAll,这会创建一个新任务,表示前两个任务全部完成。于是这里的await操作符表示接下去的代码会在前两个任务完成后再继续下去。此时控制权便还给了DoWorkAsync的调用者,不会对线程造成负担。

在未来某一时刻t1和t2会执行完,我们假设t2先结束。此时它会说:我完成了,执行回调函数/continuation吧。

于是它会和发起线程的SynchronizationContext交互,给UI线程发一个消息,让后续任务在UI线程上继续执行──您的代码不用关注这些。现在代码运行至SaveDocAsync上了,这是另外一个异步任务。await让代码在这里返回,线程又可以执行目前还未结束的任务了。

于是SaveDocAsync任务完成了,UI线程又获得了一个消息执行后续工作。

此时任务便到达了ProcessFeedAsync的末尾,于是t2任务结束了。

继续等待,上面的过程会再次出现,最终t1也结束了。

当t1和t2完成以后,最后DoWorkAsync任务也终于结束了。可以看到,我们逻辑流程,无论是循环还是异常捕获都是同步的,但是其中的执行过程完全是异步的。

但是这又是如何实现的?我不会在这里说太细,这又是个完整的话题了。这里有一个例子,是一个异步方法,它会调用并await另一个异步方法。

而编译器则最终则生成类似于这样的代码。我只会提几点,首先,这是个状态机,编译器构造的其实就是个状态机,例如迭代器就是个状态机,事实上这里编译器的工作和yield之余迭代器的重写本质上没有太大区别。

其次就是关于任务的执行和等待,假如在等待时任务已经完成了,那么其实您是在同步地执行后续代码。我们没有必要交还控制,反正已经完成了,我们不妨就直接进行下去了。await有自己的模式,会决定这一任务是同步还是异步地执行。对于同步执行的任务,一切就继续执行下去了,直到某个需要异步执行的地方,便把控制权交还给调用方。

那么我们再来看一下异步之于Web服务的意义。这里有个ASP.NET页面,它会向数据库里获取许多RSS地址,然后下载到本地并解析:

private void ProcessData()
{
    // ...

    var urls = new List<string>();
    using (var conn = new SqlConnection(connectionString))
    {
        conn.Open();
        var cmd = new SqlCommand("GetUserFeeds", conn);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@UserID", user);
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read()) urls.Add(reader["FeedURL"].ToString());
        }
    }

    var feeds = (from url in urls select CreateWebClient().DownloadString(url)).ToArray();

    // ...
}

这里用到了DownloadString这个同步下载数据的方法。执行下来大约要花费1秒多的时间。这里我不再演示令人痛苦的异步写法了,你必须在Page_Load和Page_PreRender各写一些逻辑,注册一些异步工作,或者就要启用一些后台线程,但这又会影响后台的线程池,对系统的表现会带来影响。

现在我来演示一些简单的异步化工作:

private async void ProcessData()
{
    // ...

    var urls = new List<string>();
    using (var conn = new SqlConnection(connectionString))
    {
        conn.Open();
        var cmd = new SqlCommand("GetUserFeeds", conn);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@UserID", user);
        using (var reader = await cmd.ExecuteReaderAsync())
        {
            while (reader.Read()) urls.Add(reader["FeedURL"].ToString());
        }
    }

    var feeds = await TaskEx.WhenAll(
        from url in urls select CreateWebClient().DownloadStringTaskAsync(url));

    // ...
}

我们将DownloadString修改为DownloadStringTaskAsync,这样LINQ返回的就是一系列表示下载任务的Task对象,然后使用await及WhenAll等待它们全部完成。数据库查询也可以如此。这就是所有我们要做的事情。如今页面的执行效率有了很明显的提高。使用这个做法,我们可以很轻松地提高Web系统的伸缩能力。如今我们需要调用很多互相独立的服务的情况越来越多了,异步方法对此有很大帮助。

如今的异步场景有许多种,例如在后台执行一个计算任务,这是基于CPU的异步,还有基于网络或I/O的异步任务。这些都能用Task来表示出来,因为Task表示的就是未来会完成的异步任务。此外,有了async和.NET框架,我们则出现了另外一种任务,既基于某些任务组合而成的异步任务。这也就是async方法所体现出的异步任务,它可以让你使用传统的语句来构造异步执行过程。

例如有这么一个场景:获取链接,根据链接下载Youtube视频,根据下载到的视频创建mashup并组合起来。在执行这些工作的时候,我们也希望UI可以响应用户操作。

而要完成这些工作,代码可能只需要这么简单,完全就像同步代码一样。而这里也体现了多种异步任务:ScrapeYoutubeAsync是网络密集型任务,然后同时下载两个视频并等待它们结束。然后MashupVideosAsync是CPU密集型任务,然后最后则是I/O密集型的的SaveAsync操作。对于异常处理来说,我们可以简捷地使用一个try...catch,就像传统编程那样。

总结一下,一个异步方法可以让代码和同步实现一样简单,并统一了计算、网络及I/O的异步化。这可以用来创建高度伸缩的服务器程序,自然还有响应度高的UI程序。

在演讲的末尾,我会给出Visual Studio Async CTP的下载链接,我很乐于得到大家的反馈。

相关文章

相关 [pdc visual basic] 推荐:

PDC 2010:C#与Visual Basic的未来(上)

- Mikel - 老赵点滴 - 追求编程之美
PDC不愧为微软最高级的技术人员专业会议,看得我直呼过瘾. 前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说,谈论了未来C#和VB中最为重要的两个特性:“异步(Async)”及“编译器即服务(Compiler as a Service)”.

PDC 2010:C#与Visual Basic的未来(中)

- Mikel - 老赵点滴 - 追求编程之美
前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说,谈论了未来C#和VB中最为重要的两个特性:“异步(Async)”及“编译器即服务(Compiler as a Service)”. 我现在对这场演讲进行总结,但不会像上次《编程语言的发展趋势及未来方向》那样逐句翻译,而是以Anders的角度使用一种简捷合适的方式表述其完整内容.

二十年顺风顺水:Visual Basic生日快乐!

- FiO_chn - cnBeta.COM
猛然回首才发现,Visual Basic语言已经走过了二十个寒暑. 在这二十年中,它发展成为世界上使用人数最多的一种语言,而且至今仍然没有任何衰退的趋势. 在此我们也衷心地祝愿VB能够越走越好. 1991年5月20日,微软推出了Visual Basic 1.0版,当时引起了很大的轰动. 这个连接编程语言和用户界面的进步被称为Tripod(或者Ruby),最初的设计是由阿兰・库珀(Alan Cooper)完成的.

《Visual Studio插件》(Whole Tomato Visual Assist X)v10.6.1859.0[压缩包]

- Bai - 软件 VeryCD电驴大全 - 电驴资源订阅
中文名: Visual Studio插件. 英文名: Whole Tomato Visual Assist X. 版本: v10.6.1859.0. 制作发行: Whole Tomato Software, Inc.. 问题反馈: http://www.wholetomato.com/support/default.asp.

Visual Studio 2012和.NET Framework 4.5发布

- - 博客 - 伯乐在线
摘要:好消息,微软负责Visual Studio部门的公司副总裁Jason Zander发表博客,宣布Visual Studio 2012和.NET Framework 4.5现在已经可以下载,同时提供MSDN订户、付费版本、试用版和免费Express版. 此外,他还列举了升级到Visual Studio 2012的十二大理由.

轻松编程 微软发布Small Basic 1.0正式版

- DayuLu - cnBeta全文版
Small Basic是微软两年前推出的一款免费的Basic语言开发环境,非常适合青少年和初学者,它提供了一些简单的命令,界面也很干净. 经过两年的测试,微软 本周终于发布了Small Basic 1.0正式版. 微软自己也承认,其中仍然有很多功能还有待完善,不过Small Basic的核心功能已经基本完善,能够满足新手的使用了.

分享一些非常好用的Visual Studio扩展

- 尖头叉子 - 博客园-首页原创精华区
作者: 李永京 发表于 2010-06-11 22:57 原文链接 阅读: 4189 评论: 37. Visual Studio 2010新增“扩展管理器”的功能,可用于添加、移除、启用和禁用Visual Studio扩展. 我们可以从Visual Studio Gallery(Visual Studio库)网站上安装扩展,这些扩展一般是VSIX包格式,包括项目模板、项模板、工具箱项、托管扩展框架(MEF)组件和VSPackage.

微软发布最新开发工具Visual Studio LightSwitch

- ghx88 - cnBeta.COM
感谢1美元PaypalVPS的投递. 微软向微软开发人员网络(MSDN)用户发布了最新的软件开发工具Visual Studio LightSwitch. 这个开发工具利用模板和快捷键简化商务应用程序的开发. LightSwitch是面向对编程艺术不太精通的商务应用程序开发人员的一个新工具.

可视化格式模型( Visual formatting model)再学习

- - 进步博客
“理论不懂就实践,实践不会就学理论”,非常赞同bluedavy的这句话. 实践过程中经常会遇到某个属性的使用,浏览器渲染效果与预期效果不符,虽然通过死记硬背能避免或巧妙应用这种效果,但总感心虚发慌、毫无自信,因为不知晓背后的原理. 这时就不要再用“就是这样的”的借口来搪塞自己,我们需要重新认识它. 元素A,C绝对定位,不设置top,bottom值;.