diff options
| author | BigCoke233 <hi@guhub.cn> | 2025-12-04 00:05:50 +0800 |
|---|---|---|
| committer | BigCoke233 <hi@guhub.cn> | 2025-12-04 00:05:50 +0800 |
| commit | 183bb7aff5eeae89934785ebcd35526ae0445f68 (patch) | |
| tree | 17bf07239916620b01d967e055efb62af5905fea /content/_drafts | |
| parent | 123b121ec7d0c03df199e9e23c3479ea80a81c24 (diff) | |
docs: update markdown files (2025-12-04 00:05:50)
Former-commit-id: 2cd0975c3ca4a26634309248bf4f97390cd81267
Diffstat (limited to 'content/_drafts')
| -rw-r--r-- | content/_drafts/一个电梯调度算法.md | 194 | ||||
| -rw-r--r-- | content/_drafts/极简的本质是控制.md | 29 |
2 files changed, 0 insertions, 223 deletions
diff --git a/content/_drafts/一个电梯调度算法.md b/content/_drafts/一个电梯调度算法.md deleted file mode 100644 index 8b3d9e04..00000000 --- a/content/_drafts/一个电梯调度算法.md +++ /dev/null @@ -1,194 +0,0 @@ ---- -title: 一个电梯调度算法 -subtitle: -tags: - - 计算机 - - 算法 -related_cards: -mentioned_books: -date: 2025-06-13T23:19:00 -categories: -banner: -draft: true -toc: true ---- - -作为一个程序员,我在博客上写的技术文章还是太少了,原因大概有两个:一是自己的技术水平还不足以产出太多原创内容;二是觉得计算机领域的知识很难写成所有人都能读懂的文章——总之就是,不想写枯燥的操作教程,也不想在博客上复制粘贴代码。不过最近倒是有了一些可以成文的想法。 - -[搬家](/posts/逃离群居生活/)之后,我每天都要乘电梯。尽管公寓楼的人流量比较小,基本不会出现与其他使用者争夺电梯资源的情况,但就算是这样,楼栋的电梯调度方式依然让我感到迷惑。这几天我一直尝试搞清楚电梯的运作模式,想着能不能用伪代码的方式表示出来,甚至做一些改进。好巧不巧,最近关注的一个博主就发了一篇有关电梯交互和调度算法的[文章](https://blog.codingnow.com/2025/06/elevator.html),我了解到**几乎每一个需要乘电梯上班的程序员都思考过这个问题**,还挺奇妙的。<!--more--> - -## 用户如何与电梯交互 - -回想一般坐电梯的过程:在某一层按下电梯按钮——电梯来到你所在的楼层——进入电梯后按下楼层按键——电梯带你前往你想要前往的楼层——你走出电梯,结束。 - -先把乘坐电梯的人都抽象为用户(`User`),电梯就表示为 `Elevator`,方便之后的描述。在上述交互过程中,用户会向系统输入两个指令: - -1. 在进入电梯前按下按钮,表示自己需要**向上**还是**向上** -2. 在进入电梯后按下按钮,表示自己需要去**哪一层** - -将第一个指令命名为 `Direction`,第二个指令命名为 `Destination` 或 `to`。除了这两个输入,影响电梯行为的其实还有用户所在的楼层,命名为 `Location` 或 `from`,也作为输入的一部分传给电梯的相关模块。 - -表示为伪代码: - -```javascript -user.getDirection() -user.getDestination() -user.getLocation() -``` - -电梯的交互逻辑就是这样。[云风](https://blog.codingnow.com/2025/06/elevator.html)在他的文章中提出可以用「召唤按钮」代替常见的上和下两个按键,这个可以先搁在一边,回头再看看。 - -电梯的调度算法就需要处理这三个输入,然后确定电梯的移动方式,即向上移动还是向下移动,途中在哪个楼层停下并开门。电梯本身的属性也要考虑到,包括电梯目前所在的楼层、是否可以移动(故障、超载或厢门未关闭时不能移动)。 - -```javascript -elevator.getCurrentFloor() -elevator.isMovable() -``` - -如果电梯正在响应一个用户的请求时收到了另一个用户的请求,应该先完成上一个用户的请求,还是想办法同时满足两个用户的请求,也是需要考虑的问题。同样地,这个问题先放一放,先实现基本的逻辑再说。 - -## 单用户单电梯的情况 - -调度电梯就是决定电梯如何移动,在何时调用哪一部电梯的过程。对于单部电梯来说,调度过程分为两步,也就是接和送。 - -### 接 - -假设电梯有一个 `move()` 方法,输入正数向上移动一定楼层,输入负数向下移动一定楼层。要移动到用户所在的楼层,就可以简单地表示为: - -```javascript -elevator.move(user.getLocation() - elevator.getCurrentFloor()) - -// 这显然可以封装为一个单独的函数 -elevator.moveTo = (location) => { - this.move(location - this.getCurrentFloor()) -} -``` - -使用 `moveTo()` 方法的时候就不需要再考虑电梯当前所在的位置了,因为已经被封装好了。这么看来,在单用户的情况下,单个「召唤按钮」的方案的确可以代替上和下两个按钮的方案,当用户按下按钮,只需要执行 `elevator.moveTo(user.getLocation())` 就可以了,在算法层面完全不需要考虑用户在一开始按的是向上还是向下。 - -### 送 - -送的步骤也很简单,用户进入电梯并输入目的地后,只需要执行: - -```javascript -elevator.moveTo(user.getDestination()) -``` - -似乎讲了一堆废话,单用户单电梯的情况就是很简单嘛! - -## 单用户多电梯调度 - -这更贴近我的情况,我每天都在乘电梯的时候好奇:为什么我按下了左边的电梯,响应请求的却是另一部电梯?明明左边那部电梯离我更近。 - -虽然看起来每部电梯都有各自的物理按键,但两部电梯的控制是相通的。在算法层面,用户与两部电梯是同时交互的,而不是单独地给一部电梯下达了命令。我认为这是合理的,如果有一部电梯更近,而用户按了更远的那一部,或者如果用户按下的那一部电梯正在被使用,而另一部是空闲的,让用户独立操作某一部电梯就不是什么好事。 - -总而言之,在不止一部电梯的情况下,我们依然只需要考虑单一的输入。 - -### 接 - -在有多部电梯的情况下,只需要调度一部电梯接送用户。为了最小化用户的等待时间,提高效率,选择距离用户最近的电梯就是最佳方案。由于我们正在考虑单用户的情况,所以不存在电梯繁忙、正在运送其他用户的情况。 - -这时就不能直接让 `elevator` 对象响应请求了,可能需要一个额外的电梯调度器(`elevatorScheduler`)决定让那一部电梯前去接送用户。这个调度器应该能够访问系统中所有的电梯,对比他们与用户的距离,然后派遣最近的那部电梯。 - -```javascript -// in 'elevatorScheduler' -const elevators = this.getElevatorArray() -const userLocation = user.getLocation() - -let closestElevator = null - -for (let elevator of elevators) { - const thisDistance = userLocation - elevator.getCurrentFloor() - const closetDistance = userLocation - closestElevator.getCurrentFloor() - - if (!closestElevator || cloestDistance > thisDistance) { - closestElevator = elevator - } -} - -closestElevator.moveTo(userLocation) -``` - -### 送 - -由于接到用户之后,任务就完全交给其中一部电梯了,其他电梯则不需要考虑。所以送的步骤还是和「单用户单电梯的情况」相同,在此不赘述。 - -## 多用户单电梯调度 - -我记得有一次出门,我和家人忙忙慌慌地收拾东西,把电梯一直占着,过了好久我们才下楼,走出电梯门的时候发现楼下有两个人已经不耐烦到坐在地上刷手机了,愧疚感顿时涌上心头。用户不止一个,而资源访问是互斥的,就会出现这种情况(好在电梯应该不会有死锁问题)。 - -电梯显然不能及时响应每一个用户的请求,当一个用户正在占用资源时,就不得不等待另一个用户释放资源。不过,电梯如何才算被占用呢?事实上,只有电梯厢门打开或准备打开时才算被占用,因为电梯在接和送的过程其实都可以停靠。比如,有人从一楼前往五楼,而我打算从三楼前往四楼;当电梯正在从一楼向上移动时,我在三楼按下按钮,电梯理应响应我的请求,在三楼停下打开门;当我进入电梯按下四楼按钮,它也理应在四楼停下开门让我出去,然后再送另一个用户去五楼。 - -在多用户的情况下,单个「召唤按钮」的模式就不那么好用了。还是那个例子,当有人从一楼前往五楼,我依然在三楼,但我打算下行前往一楼。这个时候,电梯不应该给我开门,应该在送完去五楼的用户之后返回时再给我开门。如果没有上行和下行按钮的区分,电梯就无法在接送时确定要不要响应用户请求,以及何时响应用户请求。 - -为什么不能在另一个用户前往五楼的时候开门,让需要下楼的我乘坐电梯呢?毕竟只要等前一个人到达目的地,电梯再响应我的请求就好了。问题在于,电梯停考和开门的过程,为了保证停靠平稳,不会出现安全问题,耗费的时间是很长的,在中途给我开门会增加其他用户的等待时间。 - -尽管电梯的上下按键可能会让人感到困惑,搞不清楚「上」指的是用户想要往上走,还是命令电梯向上运行,但这个操作逻辑在习惯之后是可以变得符合直觉的。相反,如果没有上下按键的区分,用户可能不会明白电梯为什么不响应自己的请求,自己明明想往下,而电梯却往上开。 - -### 接 - -在多用户单电梯的情况下,接和送这两个步骤变得耦合了,似乎很难完全分离开,因为当一个用户正乘电梯前往目的地时,另一个用户可能希望搭上这部电梯,接和送是同时进行的。 - -不过,我们依然先考虑电梯如何响应用户「接」请求。 - -在单用户的情况下,电梯只需要直接前往用户所在的楼层就好了;在多用户的情况下,电梯则需要排序,即先前往哪个楼层,再前往哪个楼层。我们在此假设没有人按下楼层键,「送」的算法还没有开始。 - -#### 单向运行的情况 - -在一些情况下,电梯只需要单向运行。假设电梯在 6 楼,有两个用户分别在 3 楼 和 4 楼按下了电梯的下行按钮,有另一个用户在 1 楼按下了电梯的上行按钮,那么电梯只需要一直往下,分别在对应的楼层停下就好了。当前两个用户到达了 1 楼,最后一个用户正好可以上楼。 - -#### 上下楼层都有用户呼叫的情况 - -如果电梯在 4 楼,而 2 楼、3 楼和 6 楼都有用户希望下行,电梯应该如何响应呢?如果先去离得最近的 3 楼,再去 2 楼,在把这两个用户送到一楼之后再去接 6 楼的用户,显然是不合理的;电梯应该先往上,接到 6 楼的用户后再一路向下。反之亦然,如果电梯上方和下方的楼层都有用户在等待接送,而他们选择的运送方向都是一致的,那么先向反方向运行是最有效率的,可以避免走回头路——如果当前的所有用户都希望往上,那么电梯就应该先考虑向下,然后一路向上完成运送任务。 - -听起来很美好,但真的可行吗?比较极端的例子是,电梯在 17 楼,现在 18 楼和 19 楼有用户希望向上前往更高的楼层,此时 1 楼又有用户希望往上,电梯显然不应该先去一楼。对于特别高的楼层来说,这个方法不一定能保证效率。 - -虽然不能保证效率,但「反方向优先」的方案的确保证了电梯的资源消耗最低,也就是**路线最短**。如果先接送离电梯最近的用户,电梯的总运行路线长度是 41 层楼;如果先接送反方向上的用户,电梯的总运行路线长度是 35 层楼。如果电梯的运行速度是恒定的,不考虑在每个楼层的停靠时间,路线的长度就决定了时间长短。如果要保证时间最短,就应该采用「反方向优先」的方案。 - - - -刚才我们一直假设所有用户都想去同一个楼层,那如果只有 18 和 19 楼的用户想去 20 楼,而 1 楼的用户只想去 8 楼呢? - - - -在这种情况下,「最近用户优先」的方案一共移动了 29 层,「反方向优先」的方案还是移动了 35 层。显然,「反方向优先」的方案连总运行时间都不一定能保证最小,而且无论运行时间如何,这种方案都会让高层的用户等待很久。 - -等等,他们只是想去 20 楼而已,为什么不走楼梯? - -楼梯其实也可以分摊电梯的负担,但别忘了,这两个用户还没有上电梯,他们只是按下了「上行」按钮,电梯并不知道他们要去的是 20 楼还是 40 楼。况且,电梯的制造商应该也不想培养用户走楼梯的习惯吧——这样他们还怎么卖产品? - -问题又来了,如果 18 和 19 层的用户真的是想要去 40 层呢? - - - -「最近用户优先」的方案的总路线长度是 62 层楼,「反方向优先」方案的总路线长度是 55 层楼。 - -…… - -扯了这么多,结果还是没得出多用户单电梯情况下应该如何调遣电梯。显然,「最近用户优先」和「反方向优先」的方案都有弊端,各取所长应该是最好的。 - -```javascript -if (condition) { - elevator.moveTowardsClosestUserFirst() -} else { - elevator.moveTowardsOppositeDirectionFirst() -} -``` - -那么,这个 `condition` 应该如何计算呢? - -### 送 - -## 多用户多电梯调度 - -### 接 - -### 送 - -## 一种新的电梯设想 - -能不能模仿商场里的扶手电梯(Escalator),只设置一个只上行的电梯和一个只下行的电梯呢? - ---- - -另,感觉电梯的调度其实可以让 AI 实时生成最优调度方案,编写精密的算法实在是太费脑子了。
\ No newline at end of file diff --git a/content/_drafts/极简的本质是控制.md b/content/_drafts/极简的本质是控制.md deleted file mode 100644 index 75dbaefb..00000000 --- a/content/_drafts/极简的本质是控制.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: 极简的本质是控制 -subtitle: -tags: -mentioned_books: -date: -categories: -banner: -draft: true -toc: true ---- - -「少即是多」的哲学随处可见,但这种思想已经变成不入流的**风格**了,喜欢的人不加思考地践行着(每次谈到极简,我都忍不住要批评那些只用了白底黑字和卡片分栏就自称极简的网站),不喜欢的人自然也看不上。极简这个词延伸到了各个领域,从装修到笔记方法,以至于成为了一种生活的**风格**,即生活方式(lifestyle)。 - -与其在丢掉某个东西的几个月后突然发现自己需要它,不如真的思考一下自己为什么需要把东西变少,毕竟极简本身并不是目的,也不是褒义词。「少即是多」脱离了语境是不成立的,今天的文章就来分析适用这条原则的语境之间的共性是什么。<!--more--> - -## 信息的熵增 - -熵(Entropy)这个词被滥用了,不过这个原本来自于热力学的专有名词实际上在信息论中确有定义,它是对**不确定性**的度量。本文不讨论严谨的数学,仅仅借用信息论中的概念,在极简主义的语境下使用「熵」这个词。简单来说,信息越多,我们就越不确定我们要干什么,做出决策也就越困难,因为可供选择的**可能性**太多了。 - -如果走进一间房间,房间里只有一个沙发和放在沙发上的一本书,房间给人提供的信息量是很少的,可能性也就很少。在这样一间房间里,一个人能做的就是坐在沙发上读书(排除掉一边用手指转书一边在沙发上跳舞这种疯癫选项之后)。如果这间房间里除了沙发还有盆栽、浇水壶、咖啡机、黑胶机、空气净化器和零食柜,随着信息量的增加,人的行为的可能性也就增加了,而且增加的速度并不是线性的。信息熵越高,选择就越多,做出决策所需要消耗的心理资源也就越大。看房之所以令人痛苦,就是因为可以选择的房源很多,而且每间房里需要考虑的要素太多了;如果超市里只售卖一种抽纸,那买纸巾就会变的非常简单——有时候,没得选也是一种幸福。 - -经验之谈,熵在不刻意控制的境况下会增加。如果不可以控制自己的消费,房间里就会多出来很多东西;如果看到有意思的 App 就下载,手机屏幕上就会多出来很多图标;如果经常在互联网上社交,通信软件里的联系人就会一直增加;如果一直追求增长,产品里就会多出来很多臃肿的功能;如果一直在网上冲浪,浏览器里的标签页就会一直增加,电脑屏幕上就会打开越来越多的窗口…… 熵在自然、不受控制、不被观察的情况下,会一直增加,人做决策也就会越来越困难,耗费的心力会更多,理解信息的成本会变高。在某种程度上,容忍自己视线里的信息熵增加,就是自制力低下或不加思索的体现。 - - - -## 一切都在掌控之中 - - |
