OO 第二单元总结

本文为OO 第二单元电梯作业总结,本单元主要是掌握多线程和线程安全。三次作业总的架构类似,可分为输入线程、调度线程、电梯线程。三次作业的增量迭代如下

  • 第五次作业

    • 六部电梯
  • 第六次作业
    • 可选择增加电梯,电梯的初始属性可变
    • 维修电梯,将维修电梯的乘客重新安排
  • 第七次作业
    • 新增电梯增加可达性、
    • 信号量的使用

一、同步块和锁

由于我的架构还算完善,所以每次增量较为容易,在第五次作业中使用的java语言特性synchronized,所以在后续中并没有使用读写锁等更符合本单元作业的方法。

1.同步块和锁的选择

我选择的是修饰方法,这样避免修饰代码块从而效率更高。同步块出现的原因是因为不同线程可能同时对一个对象进行读写,因此判断哪些代码需要放到同步块中,只需看一下不同线程对哪些共有对象进行了读写。有以下三种情况:

  • 读读

    • 一定不会造成线程安全
  • 读写
    • 具体分析

      • 调度器线程模拟电梯运行的时候,需要读取电梯当前楼层状态不需要加锁,避免了当前电梯所在线程在sleep从而被阻塞
      • 总的请求表WaitQueue的getEnd和setEnd是需要加锁的,避免了调度器线程读到没有结束但同时输入线程刚好结束,造成调度器一直等待没有被唤醒
  • 写写
    • 一定要加锁

由上图和上述策略,我们知道同步重点在总的请求表和各个电梯的请求表,也就是对象锁

2. 避免死锁、轮询、无效notify

死锁的出现是由于下列情况造成,当然在我的架构中只需要判断同步方法中是否又调用了其他对象的同步方法即可(并不存在)

public class A{public synchronized void aMethod(){b.bMethod();}
}
public class B{public synchronized void bMethod(){a.aMethod();}
}

在本单元作业中出现CTLE的原因可能是轮询和死循环,要注意线程的终止条件和wait条件,避免出现如下

public class A{public synchronized void a1Method(){try{wait();}catch(){}notifyAll();}public synchronized void a2Method(){try{wait();}catch(){}notifyAll();}
}

避免无效notify,例如,WaitQueue在等待时,只有加请求和setEnd的时候notify

二、调度

在往届性能评定中并没有电量这一指标,也就是说只要能把人越快送到越好。在考虑到电量之后就需要调度器的设计。以第七次作业为例调度器的中心工作:从总表中读取请求并处理,如果是乘客请求进行模拟,通过策略选择要把此请求放到哪个电梯

1.调度器模拟

对于一个请求,我们把它分别放到每一个电梯中,并模拟这种情况的耗时,只需要把原来电梯中所有的sleep换成time++即可,次过程在NightElelvator类中night方法返回把当前表中所有乘客送完总耗时,假如有6部电梯,我们一共需要模拟12次,6(电梯数量)* 2(加此请求和不加此请求)。

前两次作业中,为了加快模拟速度,我为每一部电梯模拟加此请求和不加此请求开了一个线程,但是在第七次作业却报了OutOfMeomory线程开太多了,虽然RAM用的远远少于限制,第八次作业我又改成了并行化

2.调度器策略

本质都是贪心思想,仅作出在当前情况下的最优解

  • 第五次作业我用的是电梯运送此乘客所花费的最小值,这样考虑的是用电量和运送时间,即模拟把这个请求加到此电梯队列中所花费的时间减去不加此请求所花费的时间
  • 第六次第七次我用的是所有电梯结束的最短时间,考虑的是乘客等待时间和电梯总体运行时间,即模拟把此请求放到某一部电梯,它和其他电梯运行的结束时间,然后去最短的结束时间
  • 第七次中我用了迪杰斯塔拉算法,把11层看成11个点,然后求最短路径,然后从这条路径从后往前找到第一个能从起点直达终点的中间点,用图做的话,可以自定义距离,比如我有一个请求从1楼到4楼,无法直达,可选1-2-4或1-3-4,但1-3和3-4的电梯数量更多,因此选择第二条路径,然后用第二种策略模拟。本次作业距离定义: dis = abs(floor1-floor2)/log(n(可达的电梯数))

在第五第六次作业性能分中这两种策略差不多,第七次中应该是第二种更好。

三、架构

1.UML类图(以第三次为例)

#mermaid-svg-3caiBsHKMaZNNPGI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3caiBsHKMaZNNPGI .error-icon{fill:#552222;}#mermaid-svg-3caiBsHKMaZNNPGI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3caiBsHKMaZNNPGI .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-3caiBsHKMaZNNPGI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3caiBsHKMaZNNPGI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3caiBsHKMaZNNPGI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3caiBsHKMaZNNPGI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3caiBsHKMaZNNPGI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3caiBsHKMaZNNPGI .marker.cross{stroke:#333333;}#mermaid-svg-3caiBsHKMaZNNPGI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3caiBsHKMaZNNPGI g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-3caiBsHKMaZNNPGI g.classGroup text .title{font-weight:bolder;}#mermaid-svg-3caiBsHKMaZNNPGI .nodeLabel,#mermaid-svg-3caiBsHKMaZNNPGI .edgeLabel{color:#131300;}#mermaid-svg-3caiBsHKMaZNNPGI .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-3caiBsHKMaZNNPGI .label text{fill:#131300;}#mermaid-svg-3caiBsHKMaZNNPGI .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-3caiBsHKMaZNNPGI .classTitle{font-weight:bolder;}#mermaid-svg-3caiBsHKMaZNNPGI .node rect,#mermaid-svg-3caiBsHKMaZNNPGI .node circle,#mermaid-svg-3caiBsHKMaZNNPGI .node ellipse,#mermaid-svg-3caiBsHKMaZNNPGI .node polygon,#mermaid-svg-3caiBsHKMaZNNPGI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3caiBsHKMaZNNPGI .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-3caiBsHKMaZNNPGI g.clickable{cursor:pointer;}#mermaid-svg-3caiBsHKMaZNNPGI g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-3caiBsHKMaZNNPGI g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-3caiBsHKMaZNNPGI .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-3caiBsHKMaZNNPGI .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-3caiBsHKMaZNNPGI .dashed-line{stroke-dasharray:3;}#mermaid-svg-3caiBsHKMaZNNPGI #compositionStart,#mermaid-svg-3caiBsHKMaZNNPGI .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #compositionEnd,#mermaid-svg-3caiBsHKMaZNNPGI .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #dependencyStart,#mermaid-svg-3caiBsHKMaZNNPGI .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #dependencyStart,#mermaid-svg-3caiBsHKMaZNNPGI .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #extensionStart,#mermaid-svg-3caiBsHKMaZNNPGI .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #extensionEnd,#mermaid-svg-3caiBsHKMaZNNPGI .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #aggregationStart,#mermaid-svg-3caiBsHKMaZNNPGI .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI #aggregationEnd,#mermaid-svg-3caiBsHKMaZNNPGI .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-3caiBsHKMaZNNPGI .edgeTerminals{font-size:11px;}#mermaid-svg-3caiBsHKMaZNNPGI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

start
start
start
run
addRequest
getRequest
dispatch
getRequest
contain
judge
Main
+main()
InputThread
-WaitQueue waitQueue
+run() : void
Schedule
-WaitQueue waitQueue
-HashMap elevators
-HashMap outRequestTables
-HashMap inRequestTables
-HashMap checks
+run() : void
+addEage() : void
+imitate() : int
+dispatch() : void
ElevatorThread
-Elevator elevator
+run() : void
Elevator
-int id
-int capacity
-double speed
-int access
-String status
-int floor
-int lastTime
-int direction
-blooean isMaintain
-HashMapchecks
-RequestTable outRequestTable
-RequestTable inRequestTable
-WaitQueue waitqueue
-int[] accFloor
+getAccess() : boolean
+setIsMaintain() : void
+getIsMaintain() : boolean
+updateDir() : void
+getStatus() : String
+setStatus() : void
+maintainAct() : void
+restAct() : void
+openAct() : void
+closeAct() : void
+moveAct() : void
+arriveAct() : void
+getOff() : void
+getOn() : void
+clone() : NightElevator
WaitQueue
-ArrayList requests
-boolean isEnd
-HashMap cus
-int maintainSum
+addCus() : void
+remCus() : void
+isPerEnd() : boolean
+addPerRequest() : void
+addChange() : void
+addEleRequest() : void
+addMainRequest() : void
+addMaintain() : void
+subMaintain() : void
+getMaintainSum() : int
+getRequest() : Rqeuest
+setEnd() : void
+isEnd() : boolean
+isEmpty() : boolean
+getPos() : int
+addRequestTable() : void
RequestTable
-boolean isEnd
-ArrayList cusRequests
+setEnd() : void
+isEnd() : boolean
+isEmpty() : boolean
+getSize() : int
+addInRequest() : void
+addOutRequest() : void
+getLastRequest() : CusRequest
+getOneRequest() : CusRequest
+remRequest() : void
+outWait() : void
+outNotify() : void
+isHaveOn() : boolean
+isHavaOff() : boolean
+getOnRequest() : CusRequest
+getOffRequest() : CusRequest
+getFetchStart() : int
+getInDirection() : int
+clone() : RequestTable
CusRequest
-int id
-int start
-int destination
-int realDes
+setRealDes() : void
+setDestination() : void
+getDestination() : int
+getStart() : int
+getDirection() : int
Check
-int mx
-int nx
-int nowMx
-int nowNx
+only() : void
+other() : void
+endOnly() : void
+endOther() : void

2.UML协作图(第三次作业)

#mermaid-svg-dbymjBqdiLETiYpx {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dbymjBqdiLETiYpx .error-icon{fill:#552222;}#mermaid-svg-dbymjBqdiLETiYpx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dbymjBqdiLETiYpx .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-dbymjBqdiLETiYpx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dbymjBqdiLETiYpx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dbymjBqdiLETiYpx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dbymjBqdiLETiYpx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dbymjBqdiLETiYpx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dbymjBqdiLETiYpx .marker.cross{stroke:#333333;}#mermaid-svg-dbymjBqdiLETiYpx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dbymjBqdiLETiYpx .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dbymjBqdiLETiYpx text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-dbymjBqdiLETiYpx .actor-line{stroke:grey;}#mermaid-svg-dbymjBqdiLETiYpx .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-dbymjBqdiLETiYpx .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-dbymjBqdiLETiYpx #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-dbymjBqdiLETiYpx .sequenceNumber{fill:white;}#mermaid-svg-dbymjBqdiLETiYpx #sequencenumber{fill:#333;}#mermaid-svg-dbymjBqdiLETiYpx #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-dbymjBqdiLETiYpx .messageText{fill:#333;stroke:#333;}#mermaid-svg-dbymjBqdiLETiYpx .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dbymjBqdiLETiYpx .labelText,#mermaid-svg-dbymjBqdiLETiYpx .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-dbymjBqdiLETiYpx .loopText,#mermaid-svg-dbymjBqdiLETiYpx .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-dbymjBqdiLETiYpx .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-dbymjBqdiLETiYpx .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-dbymjBqdiLETiYpx .noteText,#mermaid-svg-dbymjBqdiLETiYpx .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-dbymjBqdiLETiYpx .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dbymjBqdiLETiYpx .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dbymjBqdiLETiYpx .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-dbymjBqdiLETiYpx .actorPopupMenu{position:absolute;}#mermaid-svg-dbymjBqdiLETiYpx .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-dbymjBqdiLETiYpx .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-dbymjBqdiLETiYpx .actor-man circle,#mermaid-svg-dbymjBqdiLETiYpx line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-dbymjBqdiLETiYpx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Main InputThread Schedule Elevator start start start addRequest dispatch and addRequest not transfer and get off is tranfer and dispatch again new Elevator and start setIsMaintain put the passengers to schedule alt [[is PerRequest]] [[is AddElevator]] [[is Maintain]] setEnd if empty && end then setEnd if empty && end then turn end Main InputThread Schedule Elevator

3.架构与迭代

架构

  • 第五次作业

    • 输入线程将请求传入WaitQueue,Schedule读取并模拟加到电梯表中,电梯采取ALS策略
    • 电梯有outRequestTable和inRequestTable,分别存放电梯外和电梯内的请求
    • 电梯运行为有限状态机
    • 结束条件
      • ThreadInput 当前请求为null
      • Schedule waitQueue.isEmpty() && waitQueue.isEnd()
      • Elevator outRequestTable.isEmpty() && inRequestTable.isEmpty() && outRequestTable.isEnd()
  • 第六次作业
    • 调整电梯参数
    • 结束条件
      • ThreadInput 当前请求为null
      • Schedule waitQueue.isEmpty() && waitQueue.isEnd()&& waitQueue.getMaintainSum() == 0 即需要判断电梯是否都响应了Maintain
      • Elevator outRequestTable.isEmpty() && inRequestTable.isEmpty() && outRequestTable.isEnd()或者维修
  • 第七次作业
    • 可达性在调度器已经谈过
    • 结束条件 Schedule waitQueue.isEmpty() && waitQueue.isEnd()&& waitQueue.getMaintainSum() == 0 && cus.isEmpty()cus是<Integer,Integer> 的hashMap,存放所有乘客的id和目的地,当乘客到站后将其删除
    • 同一楼层服务数量由Check类执行,实现了类似信号量的方法

电梯状态转换

参考CO有限状态机,将电梯的行为和状态分为: end, rest, move, arrive, open, close,maintain。这样处理会在电梯线程的run中很清晰,不同状态执行不同操作并进行状态转换。

4.作业中稳定的内容和易变的内容

整体的框架还是很完整,电梯线程变化的不多,加入了maintain新状态,在乘客下车时判断是否换乘

调度器变化最大,比如更换了策略类,Add和Maintain请求都是在调度器中处理;在第七次考虑可达性后,需要规划路线等等这些都是在调度器中完成。

四、bug和debug

bug

由于第五次我就使用了调度器,导致模拟的时候可能会出现真实电梯move状态floor++但是仍在move,导致影子电梯的状态转化出现错误出现了死循环;第六次作业问题是线程资源紧张导致无法申请新的线程,还有问题是应当优先处理maintain请求和addElevator请求,出现了维修后移动超过两层的情况;第七次作业暂时没找到bug

debug

大多数debug都是死循环的bug,这是由于线程一直在run没有结束,我使用JProfiler分析CPU时间从而定位出现问题的线程由于电梯运行是状态转移,因此也能轻松定位到出现问题的状态和方法。除此之外,线程无法结束我一般使用手工打断点,即在特定的语句出输出一些语句,这样可以判断是哪些线程没有结束,之后确定原因。

五、心得体会

1. 线程安全

如非必要,勿增实体

线程之间共享的对象实体越少越好,这也就是奥卡姆剃刀的应用

读写的具体判断

在上文中已经提到有的读写是必要互斥的,有的则不必要,不能一味synchronized,也不能一律都用读写锁

2.层次化设计

电梯线程的run

这样比写很多的分支语句要清晰的多,也很容易迭代开发

public void run() {while (true) {switch (elevator.getStatus()) {case "end":return;case "rest":elevator.restAct();break;case "maintiain":elevator.maintainAct();break;case "open":elevator.openAct();break;case "close":elevator.closeAct();break;case "move":elevator.moveAct();break;case "arrive":elevator.arriveAct();break;default:return;}}}

线程和面向对象

我将电梯线程和电梯分开,线程只是为其拥有的属性提供了运行的栈空间,因此将线程和具体的事物分离是很正确的,但调取器和调度线程为了简洁合为一个。面向对象的思想进一步加深。

3. 写在最后

第五次作业为了死循环bug,最终甚至没进互测,无疑是对我的一次重大打击,bug虽小,但造成后果很严重。第五次作业投入的时间超过30小时,虽然分数不理想,但我对多线程的理解在其中也得到强化,第五次作业留下的良好架构让之后的作业少走了很多弯路(虽然之后两次还是有很长时间debug)。除此之外,debug能力也得到很大提升,通过错误数据以及断点设置,结合工具能够快速定位到问题代码,分析原因并修改。

还有一个很重要的问题,太过于依赖讨论区的评测机,在之后单元中,还是要自己写一些简易的评测机。软件的开发和测试都是尤为重要的环节,即使在未来不会从事软件行业,但测试还是一项很重要的内容。

体验失败,并战胜失败,愉快的面对每次作业

BUAA OO 第二单元总结相关推荐

  1. BUAA OO第二单元作业总结

    一.作业设计策略 (一)第一次作业设计方案 模型:生产者消费者模型 两个线程:输入线程(生产者).电梯线程(消费者) 共享对象:请求队列 退出模式:输入线程读到null,退出run,并将null传入请 ...

  2. BUAA OO 第二单元 电梯

    前言 第二单元的主要任务是模拟电梯,主要涉及调度.电梯内部运行策略.换乘等,培养多线程编程的能力. 第一次作业 第一次作业的要求较为简单,模拟6部电梯的运作以及调度即可. 分析 笔者参考了上机所给的代 ...

  3. OO第二单元(电梯)单元总结

    OO第二单元(电梯)单元总结 OO第一单元(求导)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉理解和掌握多线程的思想和方法.这个单元以电梯为主题,从一开始的最简单的单部傻瓜调 ...

  4. 【OO学习】OO第二单元作业总结

    OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...

  5. 大闸蟹的OO第二单元总结

    OO的第二单元是讲多线程的协作与控制,三次作业分别为FAFS电梯,ALS电梯和三部需要协作的电梯.三次作业由浅入深,让我们逐渐理解多线程的工作原理和运行状况. 第一次作业: 第一次作业是傻瓜电梯,也就 ...

  6. OO第二单元作业小结

    总结性博客作业 第一次作业 (1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略. 第一次作业为单电梯傻瓜调度,可以采用生产者--消费者模型,是一个有一个生产者(标准输入电梯请求),一 ...

  7. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  8. OO第二单元电梯作业总结

    目录 目录一.第一次作业分析设计策略基于度量分析程序结构二.第二次作业分析设计策略基于度量分析程序结构三.第三次作业分析设计策略基于度量分析程序结构四.分析自己程序的bug五.发现别人程序bug所采用 ...

  9. OO第二单元作业分析

    前言 这一单元关于线程安全的作业结束了,在助教提供的接口的帮助以及老师提供的设计模型的指导下,这三次作业还是相对轻松地完成了,中间也没有出现什么bug,可能就是因为简单的逻辑不容易出错吧,可惜两次都由 ...

最新文章

  1. 嬴彻再融超亿美元,宁德时代领投,领跑自动驾驶卡车行业
  2. STM32下SD卡驱动详解
  3. Android联系人Contacts详解
  4. SPSS学习系列之SPSS Statistics(简称SPSS)是什么?
  5. 论文阅读02:基于深度学习的图像细粒度分类算法
  6. 【Spring Cloud】负载均衡-Ribbon
  7. 《数值分析》学习笔记 ·003——数值计算中应该注意的几个问题
  8. 代码行云流水..这位刚高中毕业的 UP 主,告诉我人的学习能力没有上限
  9. coalesce函数_什么是SQL Server COALESCE()函数?
  10. 四分位数(Quartiles)、十分位数(Deciles)和百分位数(Percentiles
  11. 以前做过一个光标代码的梦,貌似也是个预言梦
  12. Linux安装Tomcat8并启动或停止tomcat服务
  13. 计算机网络自顶向下方法华为路由器IPV6到IPV4到IPV6的隧道及实现两端主机通信
  14. QT HTTP接收多个数据包生成图片
  15. MOSES统计机器翻译系统实现过程
  16. 永远不要忘记_它永远不会忘记一张脸
  17. 80端口被占用的解决办法
  18. Led护眼灯真的有效果吗?2022双十一最值得入手护眼台灯推荐
  19. Android 7 Nougat 源码目录结构
  20. 关于北京地区2009年度计算机技术与软件专业技术资格(水平)考试有关问题的通知

热门文章

  1. 一文讲透CabloyJS全栈框架的来龙去脉
  2. 强缓存和弱缓存是什么
  3. c++ 单例模式简介和应用场景
  4. 《演出经纪人员管理办法》修订发布
  5. 安装ubuntu16.04 LTS后无网络连接的解决方法
  6. redis缓存运行原理
  7. H5+Css3学习内容
  8. java agent模式_Java Agent的agentmain和premain方式
  9. Texlive+Vscode+Jabref 安装与配置
  10. 少儿学编程系列---如何绘制星星会眨眼睛的满天星空