BUAAOO_UnitTwo

ディレクトリ

1.設計戦略

  • 最初の宿題
  • 第二の仕事
  • 第三の宿題

2番目、3番目のジョブスケーラビリティ分析-例としてのSOLID原則

3.メトリック分析

  • 最初の宿題
  • 第二の仕事
  • 第三の宿題

4.バグ分析

V.ハック戦略

6.経験

 

はじめに

  2番目のユニットの3つの割り当ては、エレベーターの問題について繰り返し考えることです。この単元は、私たちの最初の研究であり、マルチスレッド問題との接触です。マルチスレッド問題の調査の焦点は、ロックの所有と解放です。ロックが適切に処理されないと、簡単にデッドロックが発生します。同時に、マルチスレッド操作の不確実性により、コードの記述とデバッグの難しさが大幅に増大します。

 

1.設計戦略

最初の宿題

  • 最初のオペレーションは、わずかにディスパッチできる単一のエレベーターでしたが、このオペレーションでは、コンシューマープロデューサーモデルを使用しました。
  • 最初に、トレイクラスTray、プロデューサースレッドInputProducer、およびコンシューマースレッドElevatorConsumerを構築します。この考え方は、基本的にクラスの例と同じです。
  • この割り当てでは、スケジューラーの機能を完了するためにControllerクラスを作成しましたが、設計上の考慮事項が不十分なため、最終的なスケジューリングのほとんどは依然としてエレベーター自体によって実装されています。
  • 私のスケジューリング戦略は、キューを使用して、パレットが受け取ったすべての要求を格納し、エレベーターの内部要求を使用して、エレベーターで実行されている要求を格納することです。1階に到達するたびに、要求が最初に分析され、desti == floorの場合、ドロップされます。 、スリープドアの開閉時間の後、キューを分析します(==フロアからの場合)。
  • できるだけ多くの乗客を受け入れるために、エレベーターが到着したらすぐに降車し、エレベーターがドアを閉めた瞬間に授業を受けることを選びました。
  • 私のスケジューリングパフォーマンスは許容範囲内です。ここで、主な需要の選択を改善し、単純に優先するのではなく、最長のパスに設定したいと思います。

第二の仕事

  • 2番目の操作は、最初の操作を単純に拡張したもので、エレベーターの数を1〜5に無制限に変更し、最大乗客数を設定します。
  • 私はまだ最初の仕事の基本的な考え方を採用しました。最初のエレベーター番号入力を処理した後、メイン機能に戻り、次に開始する必要があるエレベーターを決定します。
  • 私のスケジューリング戦略は、受信したすべてのリクエストを開始エレベーターに分配することです。具体的な操作は、リクエストのシリアル番号の係数を取得し、残りに従って別のエレベータートレイに分割して処理を待機することです。残りのステップは、最初のジョブとほとんど同じです。
  • まず、トレイトレイクラスを5回インスタンス化して、さまざまなエレベーターの保留中の要求のリストに対応させます(一部が必ずしも使用されない場合でも)。入力スレッドでは、InputHandlerが順番にさまざまなエレベーターに分割されます。Elevatorクラスは最初のジョブに基づいています最大乗車定員を示すmaxnum属性を追加します。乗客処理中、乗客定員の変化に注意を払う必要があります。満員になると、乗客ではなくなります。
  • 乗客の数と効率を上げるために、下車してから搭乗する必要があることに注意してください。
  • スケジューリングのパフォーマンスは平均的でした。この共有戦略を選択する前に、状況に応じてエレベーターを利用して顧客をつかみましたが、結局、マルチスレッドの処理が不十分なため、依然として多くのバグが発生しました。平均的なパフォーマンスを選択しました。しかし、正確さと安定性の戦略。

第三の宿題

  • 2番目の操作に基づいて、エレベータは3つのカテゴリに分類されます。それぞれのカテゴリには、異なるリフト時間、最大乗客数、およびエレベータの乗場階があります。乗客の搭乗リクエストに加えて、特定のエレベーターを追加するリクエストが入力に追加されました。
  • このジョブを前の2つのジョブと同じ方法で記述したのではなく、代わりにスケジューラクラスControllerを書き直して、InputHandler入力スレッドとElevatorエレベータースレッドを作成しました。エレベーターを追加する要求により、InputHandlerスレッドで新しいスレッドが開始されました。
  • 今回使用した乗り換え戦略は、乗客のリクエストとデスティがどのエレベーターパーキングフロアのタイプであるかを特定し、リクエストを中間フロアと中間フロアデスティに分割することです。転送の中間フロアは、特定の状況は、たとえばカテゴリーAに属するリクエスト、カテゴリーBに属するdestiから選択されます。中階は距離に応じて1または15を選択でき、BCカテゴリーは1または5を選択できます。
  • 新しいエレベーターがある場合は、乱数が設定され、元のエレベーターと同じ種類の新しいエレベーターにリクエストが分割されます。
  • このディスパッチのパフォーマンスは許容範囲内です。次の割り当て要求は改善できるようです。単純に分割されるのではなく、距離に応じて近いエレベータの保留中の要求に分割されます。

 

2番目に、3番目の操作のスケーラビリティ分析-例としてのSOLID原理

  1. SRP単一機能原理:
    • エレベータースレッド、プロデューサースレッド、スケジューラスレッドの機能を分離し、それぞれの役割を果たします。基本的には、単一の機能の原則を満たします。
    • プロデューサースレッドは、パッセンジャーリクエストと新しいリクエストを読み取り、対応するグローバルキューに追加することのみを担当します。
    • エレベータースレッドは、ディスパッチャから要求を取得し、要求を実行する役割を果たします。
    • スケジューラスレッドは、要求に応じて異なるエレベーター要求キューに分散する役割を果たします。
    • 如要对第三次作业继续进行扩展设计,那么这几个类的主要功能代码依然可以复用,因此这一设计是可扩展的。
  2. OCP开闭原则:LSP里氏替换原则:未使用继承。
    • 前两次作业的调度职责主要由电梯负责,第三次作业分出了对应的调度器线程,这部分工作几乎是从头做起的,可见前两次作业中没有满足这一原则的要求,仍然面临了重构的问题。
    • 若要对第三次作业进行复用,可能需要对调度器的调度算法进行改进,除此之外应该不会存在大的改动,也是可以扩展的。
  3. LSP里氏替换原则:未使用继承。
  4. ISP接口隔离原则:未使用接口。
  5. DIP依赖反转原则:未使用抽象类。

 

三、度量分析

第一次作业

  • UML类图

      

  • 复杂度分析

      

      

      

  • 优缺点点评:
    • 优点:各个类的分工较为明确;
    • 缺点:可以看出controller类和电梯类的复杂度过高,本次作业中电梯确实承担了过多的指责,而没有完全发挥调度的作用。
  • UML时序图

 

 

第二次作业

  • UML类图

 

  • 复杂度分析

  • 优缺点
    • 基本上复用了上一次的代码,做到了程序的可扩展;
    • 电梯类仍然承担着过多职责,因此复杂度很高;
    • 由于实行分摊策略,因此需要在输入线程中将请求加至不同托盘里,因此也有复杂度过高问题。
  • UML时序图

 

第三次作业

  • UML类图

 

  • 复杂度分析

  • 优缺点:
    • 真正做到了调度器指责与电梯职责的分开;
    • 输入线程中由于还增加了新增电梯的请求,因此复杂度比较高;
    • 调度器和电梯线程都存在复杂度过高的问题,想来是我的很多功能的实现出现了代码重复、职责分区不明等问题。
  • UML时序图

 

四、Bug分析

  • 第一次作业强测与互测均未出现bug;本地刚开始中测时,出现过WA和超时等问题,分析后发现是自己对于多线程理解不到位,导致一些wait和notify命令用错,均已改正。
  • 第二次作业强测与互测均未出现bug。
  • 第三次作业强测和互测中都出现了玄学的WA,提示是乘客State问题,本地进行多次测试都未复现,无奈之下一字不改交上去debug,又都AC了,经了解不少同学也都有这样的情况,想来多线程确实容易出现线程不安全的情况,而我的程序在某些情况下可能会出现不稳定的运行结果。

五、Hack策略

  • 第一次作业未能成功hack;
  • 第二次作业hack到两位同学WA和RTLE问题,第一位同学的WA报错和我之后遇到的情况很类似,恐怕也是线程运行结果不稳定导致的,第二位同学的RTLE可能与调度策略有关,在极端情况下可能会超时。
  • 第三次作业未能成功hack;
  • 多线程作业的调试难度很大,我在本单元的hack中主要采用的是手动构造测试数据集的方法。

六、心得与体会

  本单元的电梯调度作业让我对多线程相关知识有了较为深入的了解。刚写第一次作业时觉得很无从下手,主要是没能很快的把刚学的多线程知识立马运用到实际应用中去,所以导致了第一次作业设计和架构上的不完善(例如没能实现完整的调度器功能),第二次作业时其实完全有时间完善一下第一次作业的构造,但发现均摊思想几乎不用动之前的构造时,还是摸鱼了(下场就是扬了性能分)。第三次作业由于电梯种类发生变化,这才不得不写出了完整的调度。每一单元的第一次作业还是尽量要完善自己的代码做到功能分开,并留出可扩展的空间。

       我对线程安全的理解是:当多个线程访问共享变量时,要通过对象锁和wait、notify方法做到一个对象在同步块内只能被一个线程访问;此外还要避免轮询问题,防止出现CPU超时。

       感谢讨论区同学慷慨分享的知识与见解,也感谢研讨课上不少同学分享出的专题研讨,这些都给了我不少的启发和收获。

 

おすすめ

転載: www.cnblogs.com/HildaChen-/p/12709698.html