LAMBDA表达式异步算法加速

上传人:woxinch****an2018 文档编号:39309073 上传时间:2018-05-14 格式:DOCX 页数:8 大小:24.33KB
返回 下载 相关 举报
LAMBDA表达式异步算法加速_第1页
第1页 / 共8页
LAMBDA表达式异步算法加速_第2页
第2页 / 共8页
LAMBDA表达式异步算法加速_第3页
第3页 / 共8页
LAMBDA表达式异步算法加速_第4页
第4页 / 共8页
LAMBDA表达式异步算法加速_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《LAMBDA表达式异步算法加速》由会员分享,可在线阅读,更多相关《LAMBDA表达式异步算法加速(8页珍藏版)》请在金锄头文库上搜索。

1、快速选出矿石 - LAMBDA 表达式异步算法加速2015-12-30Mablo技术专栏0捏饼干问题捏饼干问题前一阵学习计算机组成原理,在学习异步的时候,讲到这样一个问题。不知道童鞋们是否还记得:某小男同学要烤饼干。捏饼干需要 5 分钟,烤饼干需要 15 分钟。那么,小男同学需要20 分钟就可以吃到饼干了。现在小男同学想要量产饼干,他想吃很多饼干,他可以先捏 5 分钟饼干,再烤 15 分钟饼干。烤饼干的过程可以选择捏下一盘饼干。那么,他每 15 分钟就可以产出一抽屉饼干。这似乎已经是极速了。而这个问题在我实际项目设计上确实遇到了,而且问题就在于:产饼干太慢产饼干太慢。矿石分析实际问题矿石分析实

2、际问题问题是这样的:现有一个矿石分析系统。矿石分析系统将遍历所有可能的矿石组合,然后判断这种矿石组合是否满足我们设置的条件。因此,我们需要先求出所有矿石组合,假设需要 5 分钟。再对矿石组合进行检测,需要 15 分钟。因此,整个程序运行结束需要 20分钟,完成一次矿石分析。当然,我们想到的解决方法可能是在矿石检测的时候就已经可以对下一次用户输入进行求矿石组合。但这并没有什么卵用。就像小男同学的饭店里有一位客人在等待吃饼干,小男同学最快也只能 20 分钟才端上来烤好的饼干。原算法伪代码原算法伪代码对于这个算法加速,我想了很久。最终还是想到了一个更快的算法,在题设条件下快了5 分钟,实际上快了 9

3、0%,并且避免了内存溢出的问题。下图中的伪代码简要描述了上面的问题。其中捏饼干函数已经被发布商封装成了一个类,我们不能直接把检测代码写在里面。算法伪代码:public static Array Program()Array combinations =getArray();/需要 5 分钟,这是在捏饼干Array result =new Array();foreach(var c in combinations)/遍历需要 15 分钟,这是在烤饼干if(c.IsCorrectCombination()/这里仅仅表示执行了一些复杂的工作,这个过程比较缓慢result.Add(c);return

4、result;public static Array getArray()/捏饼干函数Array result =new Array();for 10 timesvar o = CreateCombination();/生成 10 个可以用的组合方式。这里表示捏了 10 个饼干,这个过程比较缓慢result.Add(o);return result;修改思路修改思路 之前小男同学烤饼干的方式有一个问题,就是假如小男同学一下子捏了太多太多的饼干,饼干就溢出了,烤箱根本撑不下那么多饼干。而小男同学捏完一个饼干以后,这个饼干就一直楞在那里。我的加速思路是:小男同学每捏完一个饼干,就把饼干放进烤箱里。

5、这样从小男同学开始捏饼干,到第一个饼干出烤箱,只需要只需要 15 分钟而不是分钟而不是 20 分钟分钟。(实际程序运行时捏饼干耗时非常长,并不是 5 分钟:15 分钟,而是 100 秒:10 秒,因此新算法加速了 90%左右)好像这样设计并不是很安全,小男同学每捏完一个饼干就把饼干放进烤箱,这时烤箱仍然处于工作中。也就是说我们要在程序工作的过程中给程序增加任务。目前语法上必须使用 lambda 表达式实现。而且小男同学在把手伸进工作中的烤箱时,好像可能被烤箱烫到,也要求烤箱支持一边工作一边增加饼干。因此我们对程序的设计要求很高。我们大致思路是采用 Lambda 表达式Lambda 表达式表达式

6、“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda 表达式基于数学中的 演算得名,直接对应于其中的 lambda 抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。广泛用于 Java,Python,C+和 C#。左侧写形参列表,右侧写函数体定义。主要用途是大幅度简化代码我写这篇博文不是来介绍异步编程和算法加速的。也不是来解决捏饼干问题的,今天其实是想介绍一下 Lambda 表达式的基本应用和如何应用在异步加速上面。如果你熟练使用 Lambda 表达式,可以跳过或快速浏览下面的内容。比如在 C#中,如果我们需要对一个链表进行

7、排序,先分析链表排序方法的形参列表public static IOrderedEnumerable OrderBy(this IEnumerable source, Func keySelector);这是对 IEnumerable接口的扩展方法。IEnumerable 主要表示可以被遍历的,一般集合都实现了这个接口。我们唯一需要传入的参数就是Func keySelector。如果我们在对 string 类型的链表排序,那么Tsource 就是 string。当然,TKey 显而易见就是排序的参照。这段代码怎么用我一直不懂。那个 Func 一直让新手程序员有崩溃的感觉,甚至让很多老手都不知道怎

8、么传参。而对 Func 转到定义:public delegate TResult Func(T arg);一个委托。委托的实例理解为函数的话,我们需要传入一个函数就可以了。函数必须实现 TResult Func(T arg)。在这里 T 来源于上面的TSource 泛型,在我们的问题中,我们选择 string 类型链表。链表操作示例链表操作示例 - 代码由短变长再由长变短代码由短变长再由长变短我们先简单写一下链表的构建var myList = new List();Func myOrderFunction;此时声明了委托 myOrderFunction。它应该指向一个函数(如果你理解为指向函数

9、的指针)。我们构造出这个函数。此时代码变成下面这样public static void Main(string args)Func myOrderFunction= OrderFunction;public static int OrderFunction(string input)return input.Length;之后我们对链表进行排序,调用 OrderBy 方法。直到现在我们还没有使用过Lambda 表达式,但已经完美实现了对链表排序的功能需求public static void Main(string args)Func myOrderFunction= OrderFunction

10、;var newList = myList.OrderBy(myOrderFunction);public static int OrderFunction(string input)return input.Length;说实话,无论如何,都感觉这个对链表排序的代码非常冗杂。甚至自己重新Orderby 方法都比现在这样轻松。之前我们提到了 Lambda 表达式返回一个匿名函数,左侧填写形参列表,右侧填写函数内容。我们将 OrderFunction 去掉,用Lambda 表达式定义。Func myOrderFunction = (string input) =return input.Leng

11、th;var newList = myList.OrderBy(myOrderFunction);我们声明的匿名函数只有一行,可以去掉 return 和函数体,直接在=后面书写返回值就可以。Func myOrderFunction = (string input) = input.Length;var newList = myList.OrderBy(myOrderFunction);其中我们的形参 input 可以直接省略类型Func myOrderFunction = input = input.Length;var newList = myList.OrderBy(myOrderFunc

12、tion);我们可以避开 myOrderFunction 来直接把函数塞进去。再省略一行代码var newList = myList.OrderBy(input = input.Length);此时对一个链表排序仅仅用了一行代码。我们目前排序标准是内容的长度。在实际使用时非常灵活,比如可以直接对帖子发布时间、评论量、浏览量来排序。避免了自己新写方法或重写底层,一行代码就可以搞定。回到之前的问题回到之前的问题回顾之前的问题,我们提到了算法修正。原算法是这样的,再次把伪代码传一遍public static Array Program()Array combinations =getArray();

13、/需要 5 分钟,这是在捏饼干Array result =new Array();foreach(var c in combinations)/遍历需要 15 分钟,这是在烤饼干if(c.IsCorrectCombination()/这里仅仅表示执行了一些复杂的工作,这个过程比较缓慢result.Add(c);return result;public static Array getArray()/捏饼干函数Array result =new Array();for 10 timesvar o = CreateCombination();/生成 10 个可以用的组合方式。这里表示捏了 10 个

14、饼干,这个过程比较缓慢result.Add(o);return result;此时对其进行修改,必须在每捏完一个饼干以后,即时返回这个饼干并把饼干放进炉子里,而此时捏饼干函数应该继续。因此我们简要修改捏饼干函数,去掉最后的 return,避免函数仅一次返回。public delegate void RetellIntArray(int RetellModel);public event RetellIntArray Retell;public static Array getArray()/捏饼干函数for 10 timesvar o = CreateCombination();/生成 10

15、个可以用的组合方式。这里表示捏了 10 个饼干,这个过程比较缓慢Retell?.Invoke(o);上面代码中声明了一个委托 RetellIntArray,表示在捏饼干后应该返回的事件原型。同时声明一个事件 Retell,每捏完一个饼干触发一次事件。上面利用了 C#6 的?.运算,该运算能够保证在 Retell 是 null 的时候不执行事件调用。对于程序执行的代码,我们需要在捏饼干函数每捏完一个饼干以后接受这个饼干并放进炉子里来进行下一个过程。public static Array Program()Array result =new Array();Retell += new CoreMe

16、thod.RetellIntArray(int c) =/这里可以使用异步if(c.IsCorrectCombination()/烤饼干方法。这里仅仅表示执行了一些复杂的工作,这个过程比较缓慢result.Add(c);Array combinations =getArray();/需要 5 分钟,这是在捏饼干上面的方法充分使用了事件和 lambda 表达式,将每捏完一个饼干的事件指定函数,把这个饼干烤掉。如果你还嫌慢,可以在程序方法中的烤饼干进行异步处理,每捏完一个饼干就异步烤饼干,而捏饼干函数仍然继续如果这样设计那么 5 分钟捏完饼干以后就不用管了,每个饼干都会被异步烤好,烤好后可以继续使用 lambda 和事件交给高层的代码(比如端到客户的桌子上)。另外这样设计最大好处就是饼干盒子不会溢出。过去测试经常有一种情况就是由于捏了太多饼干,而没有等捏饼干函数返回,整个计算机的内存就不足了。现在的程序工作能够

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 其它相关文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号