最初の操作-単一のマルチスレッドピギーバックエレベーター
このジョブは、設計に生産者-消費者モデルを採用します。主に、3つのタイプのインポーター、ディスパッチャー、およびエレベーターを構築します。インポーターは生産者であり、パレット、つまりディスパッチャーに継続的に要求を送信します。同時に、エレベーターは常にディスパッチャーからリクエストを取得します。入力デバイスが入力を取得できなくなり、ディスパッチャーの要求キューが空になり、エレベータがすべての乗客を目的階に送ると、エレベータは運転を停止します。この設計プロセスでは、スケジューラの必要な機能は少なく、基本的には共有キューの機能しかありません。主な運用戦略とピギーバック戦略は、エレベーターに統合されています。その中で、ピギーバック戦略は標準のALS戦略です。この設計クラス図は次のとおりです。
マルチパートマルチスレッドエレベーターの2番目のジョブシミュレーション
最初の操作と比較して、この操作では複数のエレベータが並列に実行されました。したがって、それがまだ最初の生産者-消費者モードであり、エレベータが継続的にディスパッチャを要求する場合、そのディスパッチの重要性は失われます。したがって、この操作はプロデューサー、つまり入力デバイスを使用して継続的に要求をディスパッチャに送信し、ディスパッチャは要求を各エレベータに継続的にディスパッチします。エレベーターには2つの列があります。ピックアップされる乗客列と配達される乗客列です。ディスパッチャがタスクをディスパッチした後、エレベータで送迎する乗客の列への入りを要求し、エレベータが特定の階に到達したと判断された後に送迎する乗客をピックアップしてエレベータに入ります。今回は、最初の操作と比較して、エレベータが高度な機能独立性を維持すると同時に、エレベータ内部の操作アルゴリズムがさらに最適化され、発送タスクと実行タスクがスケジューラとエレベーターに割り当てられます内部的には、ある程度の高い凝集力が得られます。この設計クラス図は次のとおりです。
3番目のマルチスレッドマルチスレッドディスパッチングエレベーター
前回の運転に比べ、以下の難点・拡大が見られます。①エレベーターが走行できる階が限られている②運転中、エレベーターを動的に増設できる。これら2つの拡張の解決策は次のとおりです。①エレベータが操作できるフロアの制限により、乗客が複数のエレベータを利用して乗換後にのみ目的地に到着する可能性がある乗換メカニズムを導入する必要があります。メカニズムを増やし、スケジューラにスレッドプールを導入し、エレベーターをスケジューラに格納し、スケジューラによってウェイクアップします。この設計プロセスでは、オブジェクト指向の思考における反復的なアイデアが適切に実装されています。主要部分は2番目の割り当てに基づいており、変更される場所は少なく、残りは2番目の割り当ての拡張機能に基づいています。 。この設計では、エレベータの内部操作機能の高度な集中化が維持されていますが、スケジューリングアルゴリズムは、貪欲アルゴリズムをある程度使用して、つまり乗換回数を最小限に抑えるために、ある程度変更されています。同時に、乗客の乗り継ぎ状況を考慮して、Personクラスを導入し、直接乗車できる乗客と乗り換えが必要な乗客に分け、乗り継ぎが必要な乗客は、エレベーターに乗り入れると仮乗り場、つまり乗換階を設置します。乗換階に到着すると、乗客はエレベーターを降りてディスパッチャに送り、ディスパッチャはそれをピックアップするエレベーターに割り当てます。この割り当てのクラス図は次のとおりです。
メソッドの複雑さは次のとおりです。
Controller.addElevator(エレベーター) | 1.0 | 1.0 | 1.0 |
Controller.Controller() | 1.0 | 1.0 | 1.0 |
Controller.InputNotEnd() | 1.0 | 1.0 | 3.0 |
Controller.Put(Person) | 7.0 | 6.0 | 7.0 |
Controller.putElevator(String、String) | 1.0 | 4.0 | 4.0 |
Controller.putPerson(Person) | 1.0 | 1.0 | 1.0 |
Controller.putRequest(PersonRequest) | 1.0 | 1.0 | 1.0 |
Controller.randomPut(Person) | 1.0 | 1.0 | 1.0 |
Controller.runAll() | 1.0 | 2.0 | 2.0 |
Controller.setKeepInput(ブール) | 1.0 | 1.0 | 1.0 |
Elevator.checkFull() | 1.0 | 1.0 | 1.0 |
Elevator.checkOpen(int) | 7.0 | 4.0 | 7.0 |
Elevator.checkOpenAble(int) | 3.0 | 2.0 | 14.0 |
Elevator.Elevator(Controller、String、String) | 1.0 | 3.0 | 4.0 |
Elevator.getCurrentFloor() | 1.0 | 1.0 | 1.0 |
Elevator.getDirection() | 1.0 | 1.0 | 1.0 |
Elevator.getTargetFloor() | 1.0 | 1.0 | 1.0 |
Elevator.keepRun() | 1.0 | 2.0 | 2.0 |
Elevator.move() | 1.0 | 2.0 | 3.0 |
Elevator.open() | 1.0 | 2.0 | 2.0 |
Elevator.outAndIn() | 7.0 | 10.0 | 12.0 |
Elevator.putRequest(Person) | 1.0 | 2.0 | 2.0 |
Elevator.run() | 1.0 | 7.0 | 7.0 |
Elevator.setDirection() | 1.0 | 1.0 | 3.0 |
Elevator.setRun() | 1.0 | 13.0 | 13.0 |
InputDealer.InputDealer(コントローラ) | 1.0 | 1.0 | 1.0 |
InputDealer.run() | 3.0 | 5.0 | 6.0 |
MainClass.main(String []) | 1.0 | 1.0 | 1.0 |
Person.getCurrentFloor() | 1.0 | 1.0 | 1.0 |
Person.getFromFloor() | 1.0 | 1.0 | 1.0 |
Person.getPersonId() | 1.0 | 1.0 | 1.0 |
Person.getTempToFloor() | 1.0 | 1.0 | 1.0 |
Person.getToFloor() | 1.0 | 1.0 | 1.0 |
Person.Person(PersonRequest) | 1.0 | 1.0 | 1.0 |
Person.setCurrentFloor(int) | 1.0 | 1.0 | 1.0 |
Person.setTempToFloor(int) | 1.0 | 1.0 | 1.0 |
合計 | 58.0 | 86.0 | 111.0 |
平均 | 1.6111111111111112 | 2.388888888888889 | 3.0833333333333335335 |
クラスの複雑さは次のとおりです。
コントローラ | 1.8 | 18.0 |
エレベーター | 3.7333333333333334 | 56.0 |
InputDealer | 3.0 | 6.0 |
MainClass | 1.0 | 1.0 |
人 | 1.0 | 8.0 |
合計 | 89.0 | |
平均 | 2.4722222222222223 | 17.8 |
このアーキテクチャのスケーラビリティに関する限り、エレベータ操作の高い独立性が維持されているため、後で新しいエレベータを導入でき、同時にエレベータをさらに追加できます。ディスパッチャーに関する限り、エレベータの内部動作ロジックを変更せずに、よりパフォーマンスの高いディスパッチャーを使用することもできます。
バグ分析
对于第一次作业而言,由于采用了while循环轮询的方式,当调度器一直没有接收到新的请求时,电梯没有采用wait操作,这就导致了在互测中产生了CPU超时的问题。
对于第二次作业而言,由于没有弄清楚System.in的机制,在主线程和输入器中均新建了System.in,这就导致有部分数据没能进入输入器,最终也导致了没能进入互测阶段。
对于第三次作业而言,出现了部分乘客在换乘后没能正确被接送到目的楼层的情况,后经分析发现是当乘客到达换乘楼层后所有电梯都关闭了的原因,因此在其后引入了translate标签,仅有换乘的乘客为0的情况,且满足之前的停止情况时电梯才会停止运行。
查找BUG策略
在查找BUG过程中,使用了python的os库和subprocess库,由subprocess库模拟输入。由于在测试数据上,仅仅只做了基本的功能性测试,因此没有发现过别人的BUG
对比和心得体会
在这三次作业中,更多地体会到了面向对象的编程思想。在设计时也更多地考虑到了一定的可拓展性,其中尤其是从第二次作业到第三次作业,并没有进行过多的修改,而只是基于原有构架的拓展,同时对于设计模式的六大原则,在设计过程中也有一定的考量,因此通过这几次作业仅就面向对象编程来讲还是有了更深入的理解。同时对于多线程编程,通过这几次的作业包括实验课,学会了较为常见的一些模式,如观察者模式,生产者消费者模式,以及Worker-Thread模式。对于加锁,解锁,以及多线程同步问题有了更为深入的理解。但同时在这次设计过程中也存在着一定的不足,例如没有在调度算法方面进行进一步的优化。但通过这几次作业,也获取到了不少的知识。