Rx与Async Task的简单对比

2023-11-18

有关Reactive Extensions的介绍可见https://rx.codeplex.com/,总的来说,你可以当它是又一个异步编程的框架,它以观察者模式实现了对数据流的的“订阅”。一个列表,一个事件,一个耗时操作的方法,等等,都可以Observe起来,并且注册它的变动(任何变动将调用IObservable的OnNext/OnError/OnCompleted方法),这就大大统一的异步编程的编程方式;同时所有Observable的对象还可以任意组合;最后,支持用Linq语法来进行投影,将各种数据流转化为你感兴趣的数据对象,总之,是值得去了解一下的。不但如此,微软还为js, python, c++, ruby各做了一套同样理念的实现,诚意满满,自信满满啊。
学习linq有101sample,也就有人为Rx做了一个101sample的网站:http://rxwiki.wikidot.com/101samples

入门示例感兴趣的可以对着101samples做,今天要演示的是rx与c#5.0引入的Task和Async来做一个编程方式和效率上的简单对比。其实task的引入已经大大方便了异步编程,不再像传统的异步编程一样要写很多丑陋的begin/end了,但是它更像的是语法糖,而Rx则做的是整合。

说一下需求,冷冷姑娘对上猇产生了兴趣,想把她的博客全部down下来,我分析了一下,这个163博客既没有提供rss全文输出,rss也只能输出到最近40条。如果从网页里翻页截取,他们又用js把请求给包装起来了,算了吧,我还是偷点懒,直接从rss里读出那40篇文章的链接,然后异步下载回来吧!这就是原始需求,现在用两种写法来干这件事。

1,先看看我怎么把rss解析出来,.net有自己的类

using (var reader = XmlReader.Create(url))
{
    var feed = System.ServiceModel.Syndication.SyndicationFeed.Load(reader);
    //feed已经取出来了,rss2.0标准,已经返成了一个对象
    //your code here
}

2, Task的写法

private async Task run()
{
    using (var reader = XmlReader.Create(url))
    {
        var result = feed.Items.Select(m => new { date = m.PublishDate, link = m.Links[0].Uri.ToString() });
        foreach (var item in result)
        {
            try
            {
                var html = await new HttpClient().GetStringAsync(item.link);
                Console.WriteLine(parse(html, item.date));
            }
            catch { }
        }
    }
}

3,Rx的写法

前面说过,任何事件/网络流/文件操作,都可以转化成一个Observable的对象

private void runrx()
{
    var sw = new Stopwatch();
    sw.Start();
    using (var reader = XmlReader.Create(url))
    {
        var feed = SyndicationFeed.Load(reader);
        //所以fee.Items可以ToObservable
        var data = feed.Items.ToObservable()
                       .Select(item => new
                           {
                               //同样,异步任务也可以ToObservable
                               txt = new HttpClient().GetStringAsync(item.Links[0].Uri.ToString()).ToObservable(),
                               pubtime = item.PublishDate
                           });//投影成了一个IObservable和一个DateTime组成的数据流
       data.Subscribe(d => d.txt.Subscribe(t => Console.WriteLine(parse(t, d.pubtime)),//OnSuccess
            e => Console.WriteLine(e.Message), //OnError
            () => Console.WriteLine(sw.ElapsedMilliseconds) //OnCompleted
            ));
        Console.ReadKey();
        sw.Stop();
    }
}

4,至于里面用到了parse方法,那是用正则在提取网页内容

这个其实可以不演示的,如果从163博客里导文章这种低概率事件正好也被你碰上了的话,下面给个参考:

static string parse(string source, DateTimeOffset date)
{
	try
	{
		Regex r = new Regex(@"<span class=""tcnt"">([^<]*)</span>[\s\S]*<div class=""nbw-blog-start""></div>([\s\S]*)<div class=""nbw-blog-end""></div>");
		var g = r.Matches(source)[0].Groups;
		//return new { title = g[1].Value, content = g[2].Value };
		return
			string.Format(
				"<!doctype html><html><head><meta charset='UTF-8'><title>{0}</title></head><body><h1>{0}</h1><p>{2}</p>{1}</body>",
				g[1].Value, g[2].Value, date.ToString("yyyy-MM-dd"));
	}
	catch (Exception)
	{
		return "";
	}
}

5,在控制台里调用:

private const string url = "http://blog.163.com/ttoonnyy_2006/rss";
private static void Main(string[] args)
{
    var p = new Program();
    //只要有参数传进来就调Rx进行测试
    if (args.Length > 0)
    {
        p.runrx();
    }
    else
    {
        var sw = new Stopwatch();
        sw.Start();
        var t = p.run();
        t.Wait();
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

当然这些代码是后来为了测试用,完成别人所托只需要在取得字符串后异步存到文档里,顺便用reveal这样的演示插件把它弄漂亮点就行了。
我做了Stopwatch,看看结果对比吧。

测试从RSS解析出所有的文章链接(40篇),然后异步下载,输出到控制台的总时间,测试十次,结果如下,单位是毫秒:
rx    task
1377    6625
1087    6678
1108    8207
1404    8647
1261    7463
1158    6876
1253    6563
1244    6656
1058    7752
1107    6230
差距还是很明显的,async这种写法上异步是异步了,但是却要await,等于是分头取,然后挨个提交,表现是什么呢?如果把上文中的日志时间打印出来,它的顺序是跟日志的产生时间一致的,而Rx而是典型的一起取一起提交,谁在前完全取决于谁快了。所以它每次的顺序是不一致的。
此外,纯语法来说,task/async写法还是门槛为0,代码也简洁很多,Rx胜在他的整合性,比如上面的例子,就把一个异步的流和一个feed里面的items给整合成了一个新的Observable对象,这种组合是有无穷想象力的。

例子很简单,有兴趣的可以在自己的编程过程中有意识地对二者做个对比。

6,问题

上例中,我没找到在Rx事件结束的时候来停止stopwatch的方法,所以在每一个subscribe的OnComplete事件里面计了次时,献计献策?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rx与Async Task的简单对比 的相关文章

随机推荐

  • Vue3.0

    teleport Teleport 提供了一种干净的方法 允许我们控制在 DOM 中哪个父节点下呈现 HTML 而不必求助于全局状态或将其拆分为两个组件
  • 《C++ Primer》学习笔记(十五):面向对象编程

    C Primer 学习笔记 十五 面向对象编程 抽象基类 访问控制与继承 构造函数与拷贝控制 文本查询程序再探 练习 面向对象编程的核心思想是数据抽象 继承和动态绑定 在C 语言中 当我们使用基类的引用 或指针 调用一个虚函数时将发生动态绑
  • python跟易语言的爬虫_用易语言写个简单的小爬虫其中的关键点

    一 请求头 ctrl L快捷键创建变量 变量名 类型 协议参数 类 POST数据类 请求头数据 文本型 协议参数 添加 v 4 52 0 请求头数据 协议参数 获取协议头数据 二 请求参数比如post 变量名 类型 请求data参数 类 P
  • 【负荷预测】基于神经网络的负荷预测和价格预测(Matlab代码实现)

    目录 1 概述 2 基于神经网络的负荷预测 Matlab实现 2 1 代码 2 2 结果 2 3 回归树模型的进一步改进 3 基于神经网络的价格预测 Matlab代码实现 4 阅读全文 Matlab代码 1 概述 这个例子演示了用MATLA
  • 《软件调试的艺术》学习笔记——GDB使用技巧摘要(3)——程序崩溃处理

    程序为什么会崩溃 内存中的程序布局 当某个错误导致程序突然和异常地停止执行时 程序崩溃 迄今为止最为常见的导致程序崩溃的原因是试图在未经允许的情况下访问一个内存位置 硬件会感知这件事 并执行对操作系统的跳转 Unix系列的平台上 操作系统一
  • VS2015下用Qt Designer创建对话框

    目录 1 Qt Designer新建文件 选择适合的模板 布局窗口 2 在右侧属性窗口修改名称为需要的名称 3 文件另存为对象名称一样的xxx ui文件 4 创建xxx cpp和xxx h文件 加入工程 也可以在qt creator中创建
  • sql-labs闯关38~45

    sql labs闯关38 45 友善爱国平等诚信民主友善爱国爱国友善平等诚信自由平等友善平等法治诚信民主民主 复习笔记1 内容 sql labs第38关 GET请求 堆叠查询注入 字符型 sql labs第39关 GET请求 堆叠查询注入
  • 30分钟从零开始搭建并部署个人知识库(超详细)

    前言 网上关于动态文档生成工具有很多如 Docsify VuePress Docute Hexo这些都是一些非常优秀的文档生成工具 本章主要介绍如何快速使用Docsify搭建一个快捷 轻量级的个人 团队文档 并且通过Github Pages
  • dracut 基本介绍

    dracut 基本介绍 dracut 维基 https dracut wiki kernel org index php Main Page http www 360doc com content 13 0428 09 12139495 2
  • 计算机网络系列五 -- 运输层详解

    1 运输层 1 1 运输层的定义 运输层是 OSI 七层参考模型的第四层 主要功能为应用层提供通信服务 它即是面向通信的最高层 也是用户功能的最底层 在计算机网络中 真正进行数据通信的是两个主机的进程 由于一个主机中有多个进程同时在通信 而
  • vc++画线段的函数_word2vec的损失函数

    虽然word2vec常被当作无监督 但是其训练过程跟有监督基本差不多 原始的word2vec暂时不考虑负采样和huffman tree 其损失函数就是多元交叉熵 多元交叉熵的公式 以传统机器学习来说 这里的Zj就是某个类别的预测概率 yj
  • 物联网嵌入式学习路线发展方向(表格一目了然)

    文章目录 一 学习路线 二 各种分类 1 软件硬件分类 2 发展方向 技术类型 对应岗位分类 2 1 芯片方向 2 2 Linux方向 3 常见板子芯片内核 4 嵌入式公司 对于小白 不知道嵌入式整个体系 学什么 顺序是什么 可以找什么工作
  • Review-MyBatis

    MyBatis 1 学习方法 MyBatis框架功能与Hibernate一样 都是持久化框架 都是操作JDBC 做ORM框架 1 MyBatis框架比Hibernate小 2 做的是针对SQL语句查询结果进行封装 2 MyBatis框架是什
  • 服务器磁盘性能多少分正常,服务器内存使用率多少为正常

    服务器内存使用率多少为正常 内容精选 换一换 当您发现云服务器的运行速度变慢或云服务器突然出现网络断开现象 则可能是云服务器的带宽和CPU使用率过高导致 如果您已经通过云监控服务创建过告警任务 当CPU或带宽利用率高时 系统会自动发送告警给
  • 微弱直流电压/电流信号的采样电路 --滤波跟随放大

    要求将待测的电压 1mV 1000mV 电流 1mA 100mA 采样出来传给单片机 我的思路是 电压采样先用放大电路放大 再进行滤波 把50Hz的交流电干扰滤除 然后再进行模数转换传给单片机 电流的话用一个采样电阻 然后对其电压采样后推算
  • 信息学奥赛一本通【1034:计算三角形面积】

    题目描述 平面上有一个三角形 它的三个顶点坐标分别为 x1 y1 x2 y2 x3 y3 x1 y1 x2 y2 x3 y3 那么请问这个三角形的面积是多少 精确到小数点后两位 输入 输入仅一行 包括66个单精度浮点数 分别对应x1 y1
  • 关于git的一些命令,实验记录

    1 下载moduleA项目代码 命令 git clone https github com wangyanan52121 moduleA git 因网络问题 可能会下载失败 多试几次 2 查看当前项目 查看tag命令 字符串排序 git C
  • 语言深入理解指针(非常详细)(三)

    目录 数组名的理解 使用指针访问数组 一维数组传参的本质 二级指针 指针数组 指针数组模拟二维数组 数组名的理解 在上 个章节我们在使用指针访问数组的内容时 有这样的代码 int arr 10 1 2 3 4 5 6 7 8 9 10 in
  • mysql如何一秒插入10万条数据

    当我们需要批量插入或者更新记录时 可以采用Java的批量更新机制 该机制允许多条语句甚至一次性提交给数据库处理 通常情况下比一句一提交处理更有效率 jdbc处理批量提交有三个方法 需要注意的是 这三种方法都要和PreparedStateme
  • Rx与Async Task的简单对比

    有关Reactive Extensions的介绍可见https rx codeplex com 总的来说 你可以当它是又一个异步编程的框架 它以观察者模式实现了对数据流的的 订阅 一个列表 一个事件 一个耗时操作的方法 等等 都可以Obse