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 | 2cd0975c3ca4a26634309248bf4f97390cd81267 (patch) | |
| tree | 4b5bbb724226c9eb7836956945eaafe111deb3d0 /content | |
| parent | 5af2f5c4c7e9d06bef4352573f943d12505612d5 (diff) | |
docs: update markdown files (2025-12-04 00:05:50)
Diffstat (limited to 'content')
| -rw-r--r-- | content/_drafts/一个电梯调度算法.md | 194 | ||||
| -rw-r--r-- | content/_drafts/极简的本质是控制.md | 29 | ||||
| -rw-r--r-- | content/essays/极简的本质是控制.md | 72 |
3 files changed, 72 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 就下载,手机屏幕上就会多出来很多图标;如果经常在互联网上社交,通信软件里的联系人就会一直增加;如果一直追求增长,产品里就会多出来很多臃肿的功能;如果一直在网上冲浪,浏览器里的标签页就会一直增加,电脑屏幕上就会打开越来越多的窗口…… 熵在自然、不受控制、不被观察的情况下,会一直增加,人做决策也就会越来越困难,耗费的心力会更多,理解信息的成本会变高。在某种程度上,容忍自己视线里的信息熵增加,就是自制力低下或不加思索的体现。 - - - -## 一切都在掌控之中 - - diff --git a/content/essays/极简的本质是控制.md b/content/essays/极简的本质是控制.md new file mode 100644 index 00000000..441d5ef1 --- /dev/null +++ b/content/essays/极简的本质是控制.md @@ -0,0 +1,72 @@ +--- +title: 极简的本质是控制 +tags: + - 认知 +date: 2025-12-04T00:05:00 +draft: false +toc: true +endnotes: + - 本文所言的「极简主义」指代一种更抽象的生活方式和思维方式,不涉及特定学科领域中的定义,比如建筑学和设计学中的极简风格,就不在本文的讨论范围内。 +--- + +「少即是多」的哲学随处可见,但这种思想已经变成不入流的**风格**了,喜欢的人不假思索地践行着(每次谈到极简,我都忍不住要批评那些只用了白底黑字和卡片设计就自称极简的网站),不喜欢的人自然也看不上。极简这个词延伸到了各个领域,从装修到笔记方法,以至于成为了一种生活的**风格**,即生活方式(lifestyle)。 + +与其在丢掉某个东西的几个月后突然发现自己需要它,不如真的思考一下自己为什么需要把东西变少,毕竟极简本身并不是目的,也不是褒义词。「少即是多」脱离了语境是不成立的,今天的文章就来分析适用这条原则的语境之间的共性是什么。<!--more--> + +## 信息的熵增 + +熵(Entropy)这个词被滥用了,不过这个原本来自于热力学的专有名词实际上在信息论中确有定义[^1],它是对**不确定性**的度量。本文不讨论严谨的数学,仅仅借用信息论中的概念,在极简主义的语境下使用「熵」这个词。简单来说,信息越多,我们就越不确定我们要干什么,做出决策也就越困难,因为可供选择的**可能性**太多了。 + +如果走进一间房间,房间里只有一个沙发和放在沙发上的一本书,房间给人提供的信息量是很少的,可能性也就很少。在这样一间房间里,一个人能做的就是坐在沙发上读书(排除掉一边用手指转书一边在沙发上跳舞这种疯癫选项之后)。如果这间房间里除了沙发还有盆栽、浇水壶、咖啡机、黑胶机、空气净化器和零食柜,随着信息量的增加,人的行为的可能性也就增加了,而且增加的速度并不是线性的。信息熵越高,选择就越多,做出决策所需要消耗的心理资源也就越大。看房之所以令人痛苦,就是因为可以选择的房源很多,而且每间房里需要考虑的要素太多了;如果超市里只售卖一种抽纸,那买纸巾就会变的非常简单——有时候,没得选也是一种幸福。 + +经验之谈,熵在不刻意控制的境况下会增加。如果不刻意控制自己的消费,房间里就会多出来很多东西;如果看到有意思的 App 就下载,手机屏幕上就会多出来很多图标;如果社交不克制,通信软件里的联系人就会一直增加;如果一直追求增长,产品里就会多出来很多臃肿的功能;如果一直在网上冲浪,浏览器里的标签页就会一直增加,电脑屏幕上就会打开越来越多的窗口…… 熵在自然、不受控制、不被观察的情况下,会一直增加,人做决策也就会越来越困难,耗费的心力会更多,理解信息的成本会变高。在某种程度上,容忍自己视线里的信息熵增加,就是对目之所及之物缺乏控制力。 + +## 一切都在掌控之中 + +在我看来,所谓的极简主义(minimalism)追求的就是将信息控制在**最小**(minimal)的可用范围内。一个很好的例子是我在[第 50 期周刊](/posts/weekly/50/)中分享的一个得体的网站所需要的最少 CSS 样式[^2],这是作者 Kevin Powell 给出的答案: + +```css +html { + color-scheme: light dark; +} + +body { + font-family: system-ui; + font-size: 1.25rem; + line-height: 1.5; +} + +img, +svg, +video { + max-width: 100%; + display: block; +} + +main { + max-width: min(70ch, 100% - 4rem); + margin-inline: auto; +} +``` + +如果阅读 Kevin 的这篇文章,你会发现他并不是在做减法,而是从零开始做加法,而做加法的标准是「只有真正必要的部分才被加进来」。文中,Kevin 列举了网站常用的元素,并根据经验论述了这些元素分别需要什么样的样式,以及为什么需要这些样式(比如优化排版、防止图片溢出、实现简单的夜间模式、限制页面宽度等)。这就是一种控制:清楚地知道自己的目的——拆解实现这个目的**必要**步骤——只执行必要的步骤。 + +对我个人而言,我希望我的设备完全在我的掌控当中,所以我会不定期查看 MacBook 上的 App 列表,卸载不常用的 App;由于命令行工具不像 GUI 应用那样方便查看,我还开发了 [wthis](https://github.com/BigCoke233/wthis) 这个小工具用于直观地展示某个 Homebrew 软件包的描述、是何时安装的、是自动作为依赖安装的还是手动安装的、与其他软件包的依赖关系等必要信息,以确保我留在 `brew list` 里的都是我清楚用途并认为应该保留的软件。这种控制的欲望,表现出来的就是所谓的「极简主义」。只不过,我在实践时所想的并非「尽可能删掉更多东西」,而是「只能够保留我认为必要的东西」。两者的区别很微妙,但绝非相同。 + +## 什么情况下应该极简? + +既然极简主义是目的明确且只保留必要步骤的自然产物,那其实就不应该有「什么时候才应该极简?」这个问题。对于一些人来说,把家里用各种装饰填满能让心情愉悦,但另一些人却看到不这种乱中有序,一些崇尚极简主义生活的人的家里空无一物,物品全部都收纳到柜子里了,而这种整洁能让他们心情愉悦。如果「让家变得令人心情愉悦」是目的,而一些人实现这一目的的必要步骤就是在家里的各个角落摆上自己喜欢的东西,那要我说,这种繁杂的生活空间所表现出来的,依旧是极简主义。 + +真正应该摈弃的,是文章一开始提到的「任由信息熵在自己的视线内增长而不加以控制」,例如,就算家里摆放的东西不多,拆掉的快递盒到处丢,碗筷扔在水槽里不洗,这依旧是一种繁杂——不过,要是有人觉得快递盒就应该堆在各个角落,等堆积到一定程度再统一处理,这种外人眼里的杂乱如果是个体思考后得出的解决方案,在我看来,就不是一种任由熵增发生的行为了。总而言之,极简的本质是控制,而控制就是观察、思考并做出行动加以干预的过程,如果个体思考后得出结论认为不需要进行干预,那就不算是有问题。 + +任由熵增发生的例子有很多,比如家中凌乱自己却浑然不知,就是缺乏「观察」这个步骤,根本没有尝试掌控自己的生活;或者做出了「观察」,但只接收到了信息而没有「思考」,也是缺乏控制的体现;如果已经做出了「我或许应该收拾一下」的思考,而「干预」始终没有发生,也是同样的道理。 + +所以,真正的问题是:这个东西我看到了,它应该在这里吗?我是不是应该保留它?或者,在一开始就要问:我有了增加某个东西的想法,这是必要的吗?我应不应该增加它? + +回忆我早年间使用 Typecho 搭建博客的经历,那个时候刚学会前端和 PHP,经常在网站的各个角落添加各种没用的元素,比如在页脚添加一个会跳动的颜表情、建站时间正计时、各种徽章图标(说真的,页脚大概是最容易被塞爆的区域了)。倒不是说这些元素本身不好,重点在于,当时我的一心为了折腾,想要变得和别的博客一样,我从未想过某些改动是否真的必要——思维过程的缺失才是致命的。在我看来,过度依赖 LLM 进行 Vibe Coding(或者 Vibe Designing 等一系列把创造活动交给 LLM 等行为)最严重的后果是自己主动让渡了控制权,根本没有想过某一段代码、某个模块是否必要,而 LLM 最擅长的就是生成长内容。 + +如今的极客死亡计划看起来似乎符合不少人对极简主义设计的定义,但我不会说它是一个极简的网站,我会说:它是一个完全受我控制的网站。 + +[^1]: 参见:[Entropy (information theory) - Wikipedia](https://en.wikipedia.org/wiki/Entropy_(information_theory)) + +[^2]: [The least amount of CSS for a decent looking site](https://thecascade.dev/article/least-amount-of-css/) |
