OO_JAVA_电梯运行模拟_单元总结
电梯运行模拟——三次作业总结
总体遵循的设计思路
逻辑解耦
电梯与调度器解耦
在我的三次电梯作业里,追求的目标都是让电梯运行与调度器分离,电梯只负责按照指令运行,目前的最终版本中,指令有UP、DOWN、OPEN、CLOSE、STILL、STOP六条。
楼层信息的存储和变更与电梯、调度器解耦
从第二次作业开始,我建立了Stage类,负责保存楼层信息;
建立了Instruction类,负责描述电梯运行的指令以及对应的Stage的变化,Instruction类中有一个枚举类型表示指令类型,一个IntFunction类型函数表示楼层索引的变化。
调度器运行流程解耦
从第二次到第三次,我的调度器的逻辑部分都是解耦成如下4个部分:
- 获取主请求,也就是分发指令的依据
- 根据主请求分发指令
- 推送指令和需要进入电梯人员到与电梯交互的数据单元
- 检测电梯返还人员,从本调度器处理队列中删除,第三次添加了:如果需要转乘,则重新插入顶层调度器
这是一个轮询机制,顺序循环并分发指令,控制电梯。
第一次电梯,蠢笨串行先到先得电梯
类方法复杂度表
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
"Main.main(String[])" | 1 | 1 | 1 |
"elevator.Dispatcher.Dispatcher()" | 1 | 1 | 1 |
"elevator.Dispatcher.getWaitingQueue()" | 1 | 1 | 1 |
"elevator.Dispatcher.printQueue()" | 1 | 1 | 1 |
"elevator.Dispatcher.run()" | 1 | 3 | 4 |
"elevator.Elevator.Elevator(int|int|int)" | 1 | 1 | 1 |
"elevator.Elevator.OutPersonThread.OutPersonThread(int|Vector)" | 1 | 1 | 1 |
"elevator.Elevator.OutPersonThread.run()" | 1 | 3 | 3 |
"elevator.Elevator.addPassenger(int|int)" | 1 | 1 | 1 |
"elevator.Elevator.getStage()" | 1 | 1 | 1 |
"elevator.Elevator.getStatus()" | 1 | 1 | 1 |
"elevator.Elevator.moveDown()" | 1 | 2 | 3 |
"elevator.Elevator.moveTo(int)" | 1 | 5 | 5 |
"elevator.Elevator.moveUp()" | 1 | 2 | 3 |
"elevator.Elevator.release()" | 1 | 1 | 1 |
"elevator.ElevatorOutput.formatOutput(Format|int)" | 2 | 2 | 4 |
"elevator.ElevatorOutput.formatOutput(Format|int|int)" | 2 | 2 | 4 |
"elevator.Person.Person(int|int|int)" | 1 | 1 | 1 |
"elevator.Person.getFrom()" | 1 | 1 | 1 |
"elevator.Person.getId()" | 1 | 1 | 1 |
"elevator.Person.getTo()" | 1 | 1 | 1 |
"elevator.TransferPersonRequest.TransferPersonRequest(Dispatcher)" | 1 | 1 | 1 |
"elevator.TransferPersonRequest.run()" | 3 | 2 | 5 |
"util.MultiMap.MultiMap()" | 1 | 1 | 1 |
"util.MultiMap.get(K)" | 1 | 1 | 1 |
"util.MultiMap.put(K|V)" | 1 | 1 | 2 |
"util.MultiMap.remove(K)" | 1 | 1 | 1 |
"util.MultiMap.toString()" | 1 | 1 | 1 |
可见的是,我的方法复杂度都很低,因为类也比较少,没什么衡量价值
第二次电梯,可捎带无限容量电梯
第二次电梯运作原理图
main ->> Dispatcher : 启动计时器、电梯调度器,然后结束
transfer ->> Dispatcher : 传递人员请求;结束时发送Person.END
transfer ->> transfer : 输入流截止便关闭
Stage -->> Dispatcher : 拿到楼层信息,计算指令
Dispatcher ->> Elevator : 发送指令,如果是开门指令,则等待人员返还
Dispatcher ->> Stage : 在发送指令后变更楼层
Dispatcher ->> Elevator : 发送待上电梯人员
Elevator -->> Dispatcher : 返还待下电梯人员
Dispatcher ->>Dispatcher : 拿到END且处理队列为空时,发送指令关闭电梯,自己也退出轮询
从第二次电梯开始,我的电梯是按照如上的设计架构完成的,这是让我觉得比较舒服的架构设计,其设计方向是在于模拟,而不是为最优解设计的。
类方法复杂度表
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
"Main.main(String[])" | 1 | 1 | 1 |
"machine.Dispatcher.Dispatcher()" | 1 | 2 | 2 |
"machine.Dispatcher.exec(Instruction)" | 1 | 7 | 7 |
"machine.Dispatcher.getNewInstruction()" | 6 | 4 | 9 |
"machine.Dispatcher.getNewMajorRequest()" | 8 | 4 | 11 |
"machine.Dispatcher.run()" | 1 | 5 | 5 |
"machine.Dispatcher.updatePersonMap()" | 1 | 3 | 3 |
"machine.elevator.Elevator.Elevator(ReentrantLock)" | 1 | 1 | 1 |
"machine.elevator.Elevator.close()" | 1 | 1 | 1 |
"machine.elevator.Elevator.move()" | 1 | 1 | 1 |
"machine.elevator.Elevator.open()" | 1 | 1 | 1 |
"machine.elevator.Elevator.run()" | 2 | 5 | 8 |
"machine.elevator.Elevator.setOutsideQueue(MapVisitor<Integer| Person>)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setStage(Stage)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setToBeExec(List<Instruction>)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setToBeRemoved(Queue<Person>)" | 1 | 1 | 1 |
"machine.elevator.ElevatorOutput.formatOutput(Format|int)" | 2 | 2 | 5 |
"machine.elevator.ElevatorOutput.formatOutput(Format|int|int)" | 2 | 2 | 4 |
"machine.elevator.Stage.Stage()" | 1 | 1 | 1 |
"machine.elevator.Stage.Stage(int)" | 1 | 1 | 2 |
"machine.elevator.Stage.apply(IntFunction)" | 1 | 1 | 2 |
"machine.elevator.Stage.checkIndex(int)" | 1 | 1 | 2 |
"machine.elevator.Stage.checkStage(int)" | 3 | 1 | 3 |
"machine.elevator.Stage.getStage()" | 1 | 1 | 1 |
"machine.input.Person.Person(int|int|int)" | 1 | 1 | 2 |
"machine.input.Person.equals(Object)" | 2 | 1 | 2 |
"machine.input.Person.getFrom()" | 1 | 1 | 1 |
"machine.input.Person.getId()" | 1 | 1 | 1 |
"machine.input.Person.getSide()" | 1 | 1 | 1 |
"machine.input.Person.getStatus()" | 1 | 1 | 1 |
"machine.input.Person.getTo()" | 1 | 1 | 1 |
"machine.input.Person.transSide()" | 1 | 1 | 2 |
"machine.input.TransferPersonRequest.TransferPersonRequest(Queue<Person>)" | 1 | 1 | 1 |
"machine.input.TransferPersonRequest.run()" | 3 | 2 | 4 |
"machine.input.TransferRequest.TransferRequest(PersonMap)" | 1 | 1 | 1 |
"machine.input.TransferRequest.run()" | 3 | 2 | 4 |
"machine.instr.Instruction.Instruction(Instr|IntFunction)" | 1 | 1 | 1 |
"machine.instr.Instruction.getFunc()" | 1 | 1 | 1 |
"machine.instr.Instruction.getInstr()" | 1 | 1 | 1 |
"util.MultiMap.MultiMap()" | 1 | 1 | 1 |
"util.MultiMap.get(K)" | 1 | 1 | 1 |
"util.MultiMap.put(K|V)" | 1 | 1 | 2 |
"util.MultiMap.removeByKey(K)" | 1 | 1 | 1 |
"util.MultiMap.removeValue(K|V)" | 1 | 2 | 2 |
"util.MultiMap.toString()" | 1 | 1 | 1 |
"util.PersonMap.PersonMap()" | 1 | 1 | 1 |
"util.PersonMap.getFromPerson(int|Status)" | 2 | 2 | 2 |
"util.PersonMap.getToPerson(int|Status)" | 2 | 2 | 2 |
"util.PersonMap.hasElement(Person)" | 3 | 3 | 4 |
"util.PersonMap.isEmpty()" | 5 | 4 | 7 |
"util.PersonMap.putPerson(Person)" | 2 | 2 | 3 |
"util.PersonMap.removePerson(Person)" | 2 | 4 | 4 |
"util.PersonMap.toEnd()" | 2 | 2 | 2 |
"util.PersonMap.toString()" | 1 | 1 | 1 |
可以看出加粗的三个方法复杂度较高,分别是获取主请求、根据主请求生成新命令、还有personMap的isEmpty方法。
获取主请求由于personMap的不合理,得在遍历时分别获取personMap的两个子map,即fromUp和fromDown两个map,所以复杂度很高。
根据主请求生成命令复杂度高跟上一个函数同理。
personMap的isEmpty方法就是因为personMap内部成员是4个map,对每一个都isEmpty然后与起来,复杂度就高了。
类复杂度表
Class | OCavg | WMC |
---|---|---|
"Main" | 1.00 | 1 |
"machine.Dispatcher" | 5.17 | 31 |
"machine.elevator.Elevator" | 2.22 | 20 |
"machine.elevator.Elevator.Format" | n/a | 0 |
"machine.elevator.Elevator.Status" | n/a | 0 |
"machine.elevator.ElevatorOutput" | 4.50 | 9 |
"machine.elevator.Stage" | 1.67 | 10 |
"machine.input.Person" | 1.38 | 11 |
"machine.input.Person.Side" | n/a | 0 |
"machine.input.Person.Status" | n/a | 0 |
"machine.input.TransferPersonRequest" | 2.00 | 4 |
"machine.input.TransferRequest" | 2.00 | 4 |
"machine.instr.InstrFac" | n/a | 0 |
"machine.instr.InstrFac.Instr" | n/a | 0 |
"machine.instr.Instruction" | 1.00 | 3 |
"util.MultiMap" | 1.33 | 8 |
"util.PersonMap" | 2.44 | 22 |
可以看出,加粗的Dispatcher类和ElevatorOutput类复杂度较高,后者不说了,这个很难避免,前者复杂度高的原因是,目前大部分的逻辑处理部分在这一层,实现了轮询生成指令并分发,又有前述的两个方法加成,所以复杂度很高,当然,这个还与我的数据结构设计有一定的关系,personMap设计得很糟糕,如果改进数据结构并分离一些逻辑,想必复杂度会降下去的吧。
第三次电梯,可达楼层、运行速度和容量均不相同的多电梯
第三次电梯运作原理图
main ->> Scheduler : 启动计时器、电梯调度器,然后结束
transfer ->> Scheduler : 传递人员请求
transfer ->> transfer : 输入流截止便关闭
Scheduler ->> Dispatcher : 启动三部电梯的调度器
Scheduler ->> Dispatcher : 发送人员请求
Dispatcher ->> Elevator : 启动电梯
Stage -->> Dispatcher : 拿到楼层信息,计算指令
Dispatcher ->> Elevator : 发送指令,如果是开门指令,则等待人员返还
Dispatcher ->> Stage : 在发送指令后变更楼层
Dispatcher ->> Elevator : 发送待上电梯人员
Elevator -->> Dispatcher : 返还待下电梯人员
Dispatcher -->> Scheduler : 返还需要转乘的人员请求
Scheduler ->> Dispatcher : 在电梯没有处理任务、scheduler没有处理任务且拿到END时,传递结束指令
这里实际上scheduler是给三个Dispatcher发送不同的人员请求但是为了说明的简易,只画了一个Dispatcher、Stage、Elevator组。
类方法复杂度表
Method | ev(G) | iv(G) | v(G) |
---|---|---|---|
"Main.main(String[])" | 1 | 1 | 1 |
"machine.Scheduler.Scheduler()" | 1 | 1 | 1 |
"machine.Scheduler.dispatchPerson()" | 1 | 1 | 1 |
"machine.Scheduler.putPersonToElevator(Person)" | 1 | 2 | 2 |
"machine.Scheduler.run()" | 1 | 4 | 4 |
"machine.elevator.Dispatcher.Dispatcher(Stage,String,long,int,ReentrantLock)" | 1 | 1 | 1 |
"machine.elevator.Dispatcher.exec(Instruction)" | 1 | 5 | 5 |
"machine.elevator.Dispatcher.getNewInstruction()" | 11 | 7 | 13 |
"machine.elevator.Dispatcher.getNewMajorRequest()" | 1 | 3 | 5 |
"machine.elevator.Dispatcher.getPeopleMap()" | 1 | 1 | 1 |
"machine.elevator.Dispatcher.run()" | 1 | 5 | 5 |
"machine.elevator.Dispatcher.setToBePut(PeopleVector)" | 1 | 1 | 1 |
"machine.elevator.Dispatcher.update()" | 1 | 3 | 3 |
"machine.elevator.Elevator.Elevator(ReentrantLock,String,long,int)" | 1 | 1 | 1 |
"machine.elevator.Elevator.close()" | 1 | 1 | 1 |
"machine.elevator.Elevator.move()" | 1 | 1 | 1 |
"machine.elevator.Elevator.open()" | 1 | 1 | 1 |
"machine.elevator.Elevator.processInside()" | 1 | 1 | 1 |
"machine.elevator.Elevator.processOutside()" | 2 | 1 | 2 |
"machine.elevator.Elevator.run()" | 2 | 5 | 8 |
"machine.elevator.Elevator.setOutsideQueue(MapVisitor<Integer, Person>)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setStage(Stage)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setToBeExec(List<Instruction>)" | 1 | 1 | 1 |
"machine.elevator.Elevator.setToBeRemoved(Queue<Person>)" | 1 | 1 | 1 |
"machine.elevator.Stage.Stage(int[])" | 1 | 2 | 3 |
"machine.elevator.Stage.apply(IntFunction)" | 1 | 2 | 2 |
"machine.elevator.Stage.checkIndex(int)" | 1 | 1 | 2 |
"machine.elevator.Stage.couldStall()" | 1 | 1 | 1 |
"machine.elevator.Stage.getStage()" | 1 | 1 | 1 |
"machine.elevator.Stage.initStage(int)" | 1 | 2 | 2 |
"machine.elevator.Stage.isReachable(int)" | 1 | 1 | 1 |
"machine.elevator.Stage.isReachableByIndex(int)" | 2 | 2 | 2 |
"machine.elevator.Stage.stageToIndex(int)" | 3 | 1 | 4 |
"machine.elevator.Stage.toString()" | 1 | 1 | 1 |
"machine.input.Person.Person(int,int,int)" | 1 | 1 | 2 |
"machine.input.Person.equals(Object)" | 2 | 1 | 2 |
"machine.input.Person.getDestination()" | 2 | 1 | 2 |
"machine.input.Person.getFrom()" | 1 | 1 | 1 |
"machine.input.Person.getId()" | 1 | 1 | 1 |
"machine.input.Person.getSide()" | 1 | 1 | 1 |
"machine.input.Person.getStatus()" | 1 | 1 | 1 |
"machine.input.Person.getTo()" | 1 | 1 | 1 |
"machine.input.Person.hashCode()" | 1 | 1 | 1 |
"machine.input.Person.isOutside()" | 1 | 1 | 1 |
"machine.input.Person.isUp()" | 1 | 1 | 1 |
"machine.input.Person.needGetInside(int)" | 1 | 1 | 2 |
"machine.input.Person.needGetOutside(Stage)" | 3 | 2 | 3 |
"machine.input.Person.setMid(Stage,Stage)" | 6 | 6 | 12 |
"machine.input.Person.toString()" | 1 | 1 | 1 |
"machine.input.Person.transSide()" | 1 | 1 | 2 |
"machine.input.Person.wantOne()" | 3 | 4 | 7 |
"machine.input.TransferRequest.TransferRequest(PeopleVector,ReentrantLock)" | 1 | 1 | 1 |
"machine.input.TransferRequest.run()" | 3 | 3 | 5 |
"machine.instr.Instruction.Instruction(Type,IntFunction)" | 1 | 1 | 1 |
"machine.instr.Instruction.getFunc()" | 1 | 1 | 1 |
"machine.instr.Instruction.getType()" | 1 | 1 | 1 |
"machine.output.Output.format(Format,int,String)" | 2 | 2 | 5 |
"machine.output.Output.format(Format,int,int,String)" | 2 | 2 | 4 |
"machine.util.PeopleMap.PeopleMap()" | 1 | 2 | 2 |
"machine.util.PeopleMap.getCapcity()" | 1 | 1 | 1 |
"machine.util.PeopleMap.getMap(Type)" | 1 | 1 | 1 |
"machine.util.PeopleMap.getPerson(Type,int)" | 1 | 1 | 1 |
"machine.util.PeopleMap.hasElement(Person)" | 3 | 4 | 5 |
"machine.util.PeopleMap.isEmpty()" | 1 | 2 | 2 |
"machine.util.PeopleMap.put(Type,Integer,Person)" | 1 | 1 | 1 |
"machine.util.PeopleMap.putPerson(Person)" | 3 | 2 | 5 |
"machine.util.PeopleMap.remove(Type,Integer,Person)" | 1 | 1 | 1 |
"machine.util.PeopleMap.removePerson(Person)" | 2 | 2 | 4 |
"machine.util.PeopleMap.toEnd()" | 1 | 2 | 2 |
"machine.util.PeopleMap.toString()" | 1 | 1 | 1 |
"machine.util.PeopleVector.PeopleVector()" | 1 | 1 | 1 |
"machine.util.PeopleVector.putPerson(Person)" | 1 | 2 | 2 |
"machine.util.PeopleVector.putPerson(Person,String)" | 1 | 2 | 3 |
"machine.util.PeopleVector.toEnd()" | 1 | 3 | 3 |
"util.MultiMap.MultiMap()" | 1 | 1 | 1 |
"util.MultiMap.get(K)" | 1 | 1 | 1 |
"util.MultiMap.isEmpty()" | 1 | 1 | 1 |
"util.MultiMap.put(K,V)" | 1 | 2 | 3 |
"util.MultiMap.removeByKey(K)" | 1 | 1 | 1 |
"util.MultiMap.removeValue(K,V)" | 1 | 2 | 2 |
"util.MultiMap.toString()" | 1 | 1 | 1 |
"util.MultiMap.values()" | 1 | 1 | 1 |
加粗的两个方法复杂度飘红了,还是蛮高的,一个是与之前一样的getNewMajorRequest方法,获取新的主请求,因为遍历对象,还有判断person的逻辑比较复杂,所以复杂度很高;
相比上回的改进是getNewInstruction方法复杂度已经没那么高了,因为将一部分逻辑引导到了person类中。
另一个是person类的setMid方法,其作用是设置person的中转目的地,因为拿取了两个stage对象并循环调用对象isReachable函数判断,所以复杂度较高,但并不是太高,只是刚刚超出。
类复杂度表
Class | OCavg | WMC |
---|---|---|
"Main" | 1.00 | 1 |
"machine.Scheduler" | 1.75 | 7 |
"machine.elevator.Dispatcher" | 3.88 | 31 |
"machine.elevator.Elevator" | 1.91 | 21 |
"machine.elevator.Elevator.Format" | n/a | 0 |
"machine.elevator.Stage" | 1.70 | 17 |
"machine.elevator.StageFac" | n/a | 0 |
"machine.input.Person" | 1.94 | 33 |
"machine.input.Person.Side" | n/a | 0 |
"machine.input.Person.Status" | n/a | 0 |
"machine.input.TransferRequest" | 2.00 | 4 |
"machine.instr.Instr" | n/a | 0 |
"machine.instr.Instr.Type" | n/a | 0 |
"machine.instr.Instruction" | 1.00 | 3 |
"machine.output.Output" | 4.50 | 9 |
"machine.util.PeopleMap" | 1.92 | 23 |
"machine.util.PeopleMap.Type" | n/a | 0 |
"machine.util.PeopleVector" | 1.50 | 6 |
"util.MultiMap" | 1.38 | 11 |
Dispatcher类有点积重难返的意思,目前架构是这样了,当然,Dispatcher类完全可以把功能分散到其他类中,最后让他起组合搭桥的作用,就是把之前就描述的DIspatcher类的四个函数分离开来,变成新的类的处理逻辑,这样,应该可以显著减少他的复杂度把;
Person类WMC过高的原因是方法太多了,获取成员、判断进出、判断上哪一个电梯,这么多内容夹杂在一起,内部还有其他的工具函数,导致Person类复杂度很高,如果重构,可以把新的person类变成几个接口的组合,一个获取ID、FROM、TO的借口,一个判断进出相关工具函数的接口,或者单独开个类,处理人员是否需要进出和向上哪一个电梯的类,后者让person专职其责,也能降低复杂度,更好一点把。
Output类。。不用说了。
第三次电梯的所有类图景
作业bug分析
从架构上来说,我的程序在线程间的数据安全上,是没有问题的,所以bug主要出现在我某一个步骤没有完成,比如在写的过程中de出的一个bug,人从电梯里出来要从电梯内部的队列中删除,如果没有删除,导致一个人会出电梯数次,诸如此类,我犯得bug都是这样的错误,这些bug的主要原因是我的数据结构类设计的不够好,使用时头脑也不清晰,可变数据的坏处就在这,必须时时考虑数据该怎么变化迁移,或是添加或是删除。
除了上述说的,我还犯得的一个bug就是主请求选择bug,第三次电梯里,主请求选择没有考虑人满员的状况,选了outside的人,导致电梯日门,哭。/(ㄒoㄒ)/~~
多线程作业感想
我从表达式求导作业完成后,就一直比较在意这个问题,就是程序的架构,还有代码的复杂度,所以在电梯作业的编写中,我就一直做着我反复说的东西,就是分离分离再分离,将逻辑分散开来,当然,不能是随意地平行散列逻辑,应该是有所关联结构,按照层次化的方式构建起来的,不断将逻辑解耦,就是我在写程序中反复思考的内容,为此,我写这部分程序动辄删除或者重写,但是由于经验和能力的不足,依然没有设计出真正健壮、低耦合、复杂度低的架构,比如我的数据结构类,设计的还是让我很不满意,也增添了我其他使用该类的方法的复杂度,这是今后需要改进的,另外我的OO工程写得实在是太慢了,从周六晚写到周二早,第二次电梯第三次电梯都是这样,第一次也少不了多少,,还是小将想指挥全军,能力不足啊。
OO_JAVA_电梯运行模拟_单元总结的更多相关文章
- OO_JAVA_表达式求导_单元总结
OO_JAVA_表达式求导_单元总结 这里引用个链接,是我写的另一份博客,讲的是设计层面的问题,下面主要是对自己代码的单元总结. 程序分析 (1)基于度量来分析自己的程序结构 第一次作业 程序结构大致 ...
- OO_JAVA_JML系列作业_单元总结
OO_JAVA_JML系列作业_单元总结 (1)梳理JML语言的理论基础.应用工具链情况 简单梳理 以下三者是jml规格里的核心,对一个方法功能和属性的限制: requires子句:规定方法的前置条件 ...
- OO_多线程电梯_单元总结
概述: 面向对象的第二单元是多线程电梯.第一次实现一部傻瓜电梯,每次只送一个人:第二次实现一部可稍带电梯:第三次实现三部可稍带电梯. 一.设计策略 1.第5.6次作业设计思路 第5.6次作业的架构相似 ...
- Spark运行模式_本地伪集群运行模式(单机模拟集群)
这种运行模式,和Local[N]很像,不同的是,它会在单机启动多个进程来模拟集群下的分布式场景,而不像Local[N]这种多个线程只能在一个进程下委屈求全的共享资源.通常也是用来验证开发出来的应用程序 ...
- Update(Stage4):Spark原理_运行过程_高级特性
如何判断宽窄依赖: =================================== 6. Spark 底层逻辑 导读 从部署图了解 Spark 部署了什么, 有什么组件运行在集群中 通过对 W ...
- 快餐店运行模拟C++程序源码代写
某快餐店供应若干种快餐和饮料(5种以上),早晨6:00开始营业,晚上11:00打烊.前一天已经安排了若干工人上班,快餐店的用餐位是固定的,每种食物的成本和销售价格是确定的,每种食物的总量是确定的,储存 ...
- 03_天气查询_socket方式模拟_多线程方式
[简述] 要重视Socket开发,企业后台服务特长使用Socket. 1.服务端要有可持续运行能力,保证线程一致在运行 2.并发处理能力,使用多线程 [工程截图] [WeatherRunner.jav ...
- OO_多项式求导_单元总结
概述: 面向对象第一单元的作业是三次难度依次递增的多项式求导.第一次作业是仅包含带符号整数和幂函数的多项式求导,例如:-1+xˆ233-xˆ06:第二次是在前面的基础上增加了三角函数的求导,例如:-1 ...
- Jmeter_前端RSA加密下的登陆模拟_引用js文件实现
版权声明:本文为博主原创文章,未经博主允许不得转载. 在一次项目实战中,前端登录使用了RSA加密,使用LoadRunner压测的第一步,就是模拟用户登录,可惜loadRunner11并不能录制前端的加 ...
随机推荐
- Identity用户管理入门五(登录、注销)
一.建立LoginViewModel视图模型 using System.ComponentModel.DataAnnotations; namespace Shop.ViewModel { publi ...
- Nginx:常用基本命令与异常处理
Nginx日志 - ./nginx-1.6.0-ems/logs/nginx.pid Nginx启动时应该使用cmd等命令行工具启动,双击启动同样会产生进程但会造成异常,判断条件是 ./nginx-1 ...
- DataGridView高度自动调整
AutoResizeGrid.cs代码 /// <summary> /// 根据行数据,自动调整DataGridView高度 /// </summary> public sea ...
- 除PerfDog之外,还有什么性能测试工具。
除PerfDog之外,还有什么性能测试工具. 高通的Snapdragon Profiler 下载地址:https://developer.qualcomm.com/software/snapdrago ...
- Linux的bg和fg和jobs和nohup命令简单介绍
我们都知道,在 Windows 上面,我们要么让一个程序作为服务在后台一直运行,要么停止这个服务.而不能让程序在前台后台之间切换.而 Linux 提供了 fg 和 bg 命令,让我们轻松调度正在运行的 ...
- XSS注入
XSS 原理: 程序对输入和输出没有做合适的处理,导致"精心构造"的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害. 分类 : 危害:存储型 > 反射型 > ...
- 学习PHP中有趣的字符集国际化验证功能
今天的内容非常简单,不过也很有趣.不知道大家有没有经历过这样的事情,就是在某些字体下,0 和 O 不好区分,1 和 l 也是很难看清楚.当然,现在大部分的编辑器和 IDE 的默认字体都是会选择那些比较 ...
- webpack4 使用babel处理ES6语法的一些简单配置
一,安装包 npm install --save-dev babel-loader @babel/corenpm install @babel/preset-env --save-devnpm ins ...
- PC+PLC通过Modbus协议构建工控系统
一. 概述 工业设备采用HMI+PLC控制是比较常见的方案,随着工业自动化的要求越来越高,现在很多设备都要求接入企业MES系统,MES系统一般为WEB系统,接口形式大部分为HTTP协议,这种传统方案和 ...
- 为Python安装Redis库
为Python安装Redis库,登陆https://github.com/andymccurdy/redis-py 后点击Download ZIP下载安装包. 解压并安装: git clone htt ...