zoukankan      html  css  js  c++  java
  • 第二次电梯作业总结

    从单线程到多线程,似乎是个思维上的跳跃。synchonised从此在我们的作业上留下了深深的烙印。一次次看到CPU time爆红,又一次次陷入死锁。不得不承认,这个过渡是及其艰辛的,甚至是直到第三次作业才有了差不多正确的认识。

    总的来说,第二部的电梯,我完成的不够好。从讨论的分享中,我明显的感受到我与dalao的差距。在我还在纠结waitnotify还在怎么用的时候,别人已经开始了各种优化,创造出了各种脑洞。我逐渐意识到,oo作业不只是作业本身,而在于你在一次次改进中逐渐去探寻最佳的解决方案。

    这次作业自己存在的一个很大的问题就是,我在没有完全弄没明白对象锁时,就胡乱的用,以至于第二次电梯就直接炸了。现在我认识到应用应是基于你非常了解的基础之上的,尤其是在几百上千的代码之上时,你的一点点理解错误就可能导致电梯直接废掉。

    不管怎样,这只是oo整个作业中的一部分而已,就算做的不太好,也只能以后加油啦。

    下面就让我来介绍一下我的电梯。

    Part 1傻瓜式电梯

    1.1具体实现

    调度策略:采用FIFO,每次搭乘一个人,然后按照先后次序去接下一个人。

    设计思想:将人分为TakerWaitertaker是电梯里携带着的人,电梯里有Waiter队列,如果电梯waiter为空,每次会调用elevator.get()去获取人,如果没有人就wait(),来人就notify

    1.2度量分析

     

    可以看出,存在的问题是,在run方法里放了太多的内容,也加入了循环,导致复杂度过高。

    1.3优缺点分析

    优点:本次作业非常简单,方法其实很单一,因此,不需要太多的优化

    缺点:部分地方复杂度过高、

    Part2 A Little Smart电梯

    终于,我们迎来了比较接近实际情况的一种电梯,甚至在我们的脑洞下,该电梯可能总的完成时间会优于现实生活中的电梯。

    但是,电梯的运行又总能因为笔者知识的有限漏洞百出。

    Action 1 电梯人口失踪神秘案件

    --喂,19004号你在哪里,我明明见你进入了等待队列,为啥没见你出来。

    Action 2 电梯罢工事件

    --电梯,我在二楼,快来接我

    --电梯,我在5楼,快来接我

    1min...

    --电梯,你是怎么啦,我还是走楼梯吧

    下面让我们来看看这些灵异事件是如何上演的

    1.1具体实现

    需求分析:电梯可以捎带人,设计一种方法,让电梯最快让所有人到达目标楼层。

    设计架构:

    我大致想到了三种设计方案

    一:每层都让能进去的都进去,每次让电梯运行到有请求(不管是请求进入还是请求到达)最高(最低)的楼层

    二:使用贪心算法。先判断电梯里的请求,每次找到最近的请求,当电梯里的请求为空时,每次找到最近的请求,当找到的请求为向上时,我们可以先判断用没有同等距离楼层的下行请求,如果上下的请求距离现在的楼层相等,就先向下再向上。同理对于找到的下行请求。

    三:每次将第一个请求作为主请求,有相同方向楼层请求时,将该请求加入到电梯中。我也做了一些小小的优化,即每次去接向上的主请求时,如果有恰好能顺路的向下的请求,就捎带上。

    遗憾的是,笔者最终中测没能通过,大概是对同步锁和wait,notify掌握的不够,最后在bug修复阶段采用的第三次作业的电梯设计。所以,我也不贴代码啥的,以免误导大家。

    由于我修复的电梯其实是采用无人数限制和楼层限制的第三次电梯,因此,我的第二部分电梯的各项分析就由第三部分代替吧。(请移步第三部分)

    下面,有我向大家我的第三次电梯。

    PART3 MULTI-ELEVATOR

    1.具体实现

    设计思路:我直接用dispatcher将请求分给了每一部电梯。对于每一部电梯,我采用了ASL策略(PART2的第三种调度方法)。而到底该怎么对请求进行分配呢?

    在分析楼层之后,我将1楼作为了所有楼层的中转站,那么请求就分为两种。一种是能直接乘坐电梯到达的请求,另一种是必须中转的请求。对于第一种请求,我直接选择了能直达的电梯。如果对于两个或者多个电梯都能到达的情况,我将请求分配给目前请求量比较少的电梯。对于中转的请求,我则将该请求的目标楼层设置为1层,并且在这个请求上做一个标签,再按照分配量最少的原则调入电梯之中。

    对于程序的结束,我设置了inputEndFlag,dispatchEndFlag,input线程接受到结束信号后,inputEndFlag会被设置,这inputEndFlagTrue并且所有电梯里都没有请求时,电梯和调度器都会停止。

    2.度量分析

    第三次作业分为两部调度,dispatch把指令调度给电梯,电梯内部对指令进行调度.

    3.优缺点

    各个线程信息交互较少,独立而安全。但是预先分配的方法,调度可能不是最优的。

    Part4 基于SOLID原则的评价

      SRP(单一责任原则):我的作业总体分为input,dispatch,elevator,person类,但在写的过程中,如第一次作业,其实有的类有些重合。但总的来说,作业基本满足单一责任原则。

      OCP(开放封闭原则):我的电梯做的比较好的部分是第三次作业每一个电梯几乎可以沿袭第二次的设计。

      LSP(里氏替换原则):在第一次作业中,waitertaker都继承了people.

      ISP(接口分离原则):作业不涉及接口问题。

    DIP(依赖倒置原则):我这个部分做的不够好。因为对接口不怎么熟悉,我没怎么使用接口。在之后的作业中,我可以尽可能去尝试接口的使用。

    PART5 分析程序bug

    第一次作业

    第一次作业由于是傻瓜调度,所以几乎没有什么bug,但是我其实对多线程模式没有充足的理解,仅仅简单的套用生产者消费者模型。

    第二次作业

    第二次作业我的中测没有过,测试中出现了各种错误,比如无法停止,cpu时间超时等等。但是,由于时间和自己知识的原因,当时对多线程的waitnotify没有深刻的理解,导致了错误。

    第三次作业

    第三次作业我的强测错了两个点。其原因都是我对于换乘的情况,我忘记了先输出output再将该人加入request表中,然后就会偶然出现还没输出某人out,就输出了某人in.

    PART5 心得体会

    相较于单线程,多线程更考验我们的设计以及我们程序设计的严谨性和周密性。同时,模块的可拓展性也是我们需要注意的地方。另一个重点就是CPU时间,我每一次上交都非常怕cpu time会爆,最终采用了牺牲性能的方法。如果有大佬有测试cpu的方法,欢迎在下方留言。第二次作业我做的真的非常不好,尽管尝试了各种方法,但还是因为自己对对象锁的理解问题,没有过。不过经过了一周的学习,在第三次作业中,我终于基本上对多线程有了比较清楚的认识,然后连同第二次作业,一起重新进行了完成。这一轮的作业,虽然挣扎,但是,我却收获满满。

  • 相关阅读:
    .NET Framework 3.0 和 Windows SDK
    用 C# 开发 SQL Server 2005 的自定义聚合函数
    IronPython 源码剖析系列(2):IronPython 引擎的运作流程
    IronPython 个人网站样例宝藏挖掘
    SetRenderMethodDelegate 方法
    使用 Castle ActiveRecord 开发发现的一些问题
    IronPython for ASP.NET CTP WhitePaper 摘要翻译
    关于 IE 模态对话框的两个问题
    逐步改用 IronPython 开发你的 ASP.NET 应用程序
    使用 Flash 和 C# WinForm 配合打造界面漂亮的应用程序(摘要)
  • 原文地址:https://www.cnblogs.com/xjm1999/p/10747860.html
Copyright © 2011-2022 走看看