n

不幂等电梯与P=NP中的分家产问题

Take my money and shut up

Posted by Zeusro on March 27, 2026
👈🏻 Select language

幂等性是程序设计的一种重要原则。

举个最简单的例子,去ATM取钱,确认好数字,按下确认之后,机器会开始吐钱。但这个过程中如果再按下“确认”, 而ATM还会接着吐钱,那么这个设计就是不幂等的。

当然现实没有那么好的事情,按下确认到收钱的这个时间段,在程序设计中属于一个“事务锁”的阶段。这期间按100次确认也是徒劳。

不知不觉之间,ATM也成为了即将被淘汰的消费电子类产品。但幂等原则和数据库事务这类基本原理没有消失。

不幂等电梯

比如我最近遇到一种“不幂等电梯”。在传统商业建筑中,运营为了方便一般会设置“1对N幂等”——按下下行之后,所有下行灯一起亮,然后调度中心分配一个最近的电梯。这种我称为“幂等电梯”。

不幂等电梯,是把面板上下行按钮跟调度中心分离。比如一栋楼有3部挨着的电梯。按下面板上的上下行,只是控制“1对1”关联的那部电梯。如果想要另外一部电梯,那就按另外一个面板。这种我称为“不幂等电梯”。 本文只讨论不幂等电梯场景。

个体自私导致群体延误

结合过往的统计规律,应用时间序列编程对“不幂等电梯”场景建模,假设工作时间是 9:00 ~ 18:30 ,那么在上下班临界点10分钟内,对于楼层<10 的写字楼,按照我的经验,基本上是走步梯比较快。

而假设场景中的人只有1个,实际上选取电梯的策略非常简单,选择“离自己最近的那部同向电梯”便是最佳策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
type Work struct {
	Floor       int16     //工作楼层
	WorkHours   time.Time //上班时间
	ClosingTime time.Time //下班时间
}

// Person 表示人
type Person struct {
	Time        time.Time // 时间
	Floor       int16     //当前楼层
	TargetFloor int16     //目标楼层
	work        Work
}

func (p *Person) MVP(elevators []Elevator) (int, *Elevator) {
	t := p.Time
	if p.work.Floor < 10 && (t.Sub(p.work.ClosingTime).Abs() < 10*time.Minute || t.Sub(p.work.WorkHours).Abs() < 10*time.Minute) {
		//walking
		return -1, nil
	}
	if len(elevators) == 0 {
		return -1, nil
	}
	distance := time.Hour << 10
	var bestElevator Elevator
	var n int
	for k, e := range elevators {
		temp := *e.Status(t)
		if d := temp.Distance(p); d < distance {
			distance = d
			n = k
			bestElevator = temp
		}
	}
	//找到离自己最近的节点并选择
	return n, &bestElevator
}

然而实际情况更多的是N人抢3部电梯这种情况比较多。这个策略会在N人情景下立刻失效。

因为“这栋楼有多少人在等电梯”对于所有不在监控室里的人来说是一个黑盒。

因此很多人会选择 “all” 策略——所有按钮一起按,甚至在下班的时候先上行再下行。即便所有人不倒着按电梯,下班的时候所有按钮都按下,也会导致下行的电梯几乎每层都停。

当然,有些人会反驳,说可以设置一个“FL”的状态,当电梯满载时一路下行不停任何楼层。 但在4人4梯时,这个问题依旧很明显——4个人分布在不同楼层,决策方向完全随机,如果所有人4个面板一起按,会造成电梯资源最大程度的浪费。

不幂等电梯揭露了一个问题:追求个体利益的最大化会损害群体利益,并最终影响到自己的收益。因为搭电梯是为了尽可能地省时间,收益函数是时间。 如果所有人都按下所有按钮,表面看来所有电梯都会朝着自己来,但最终还是导致乘梯时间最大化。

P=NP中的分家产问题

不幂等电梯代表了集体利益与个人利益的绝对矛盾。除了把电梯调整为“幂等”,让调度中心去协调之外, 似乎没有很好的解法。但如果把电梯直接量化为家产,把分配电梯当成P=NP中的分蛋糕(我个人更愿意称为“分家产”难题)。那么问题似乎简单一点。

转换一下问题,把 N 个参与人缩小为数量可控的“子女”,电梯转换为现金,那么所有参与人,彼此之间就不是“黑盒”的状态。

那么在我看来,公平分配(每个人都认为自己至少得到了蛋糕的 1/n 价值)是不存在的——假设我作为家族财产管理人,名下有几个子女。为了资产的长远递增,那就不可能全部现金N等分,然后取一份给未满18岁的儿子。

更别提每个人照镜子的时候都有自我美化倾向(曝光效应)。对自我评价比客观事实高,这是一种普遍现象。这种认知偏差,加上客观条件限制,就导致了分家产问题不可能有对所有人公平的解法。

按照历史的统计经验,分家产问题最后还是看各位继承人的投资理财水平,根据实际的财务收益和能力特长,通过时间的检验,最终才能得到一个解法。

至此,我终于理解了修格斯的分布式求偶这种行为艺术,通过广撒网,多捞鱼的渣男策略,实现面向时间效率优化的多对象差异学习梯度下降。

近水楼台先得月

A little closer to the bank, Where coins and notes are in the rank.

Idempotency is an important principle in program design.

Take the simplest example: withdrawing cash from an ATM. You confirm the amount and press “confirm”, then the machine starts dispensing money. But if pressing “confirm” again during this process makes the ATM continue dispensing, then this design is non-idempotent.

Of course, reality is not that generous. The time window between pressing confirm and receiving cash belongs to a “transaction lock” phase in program design. During this period, pressing confirm 100 times is still futile.

Before we noticed it, ATMs also became consumer electronics that are about to be phased out. But principles like idempotency and database transactions have not disappeared.

Non-idempotent Elevator

For example, I recently encountered a kind of “non-idempotent elevator”. In traditional commercial buildings, operations usually set up a “1-to-N idempotency” model for convenience: after pressing down, all down indicators light up together, and then the dispatch center assigns the nearest elevator. I call this an “idempotent elevator”.

A non-idempotent elevator separates the up/down panel buttons from the dispatch center. For instance, if a building has 3 adjacent elevators, pressing up/down on one panel only controls the “1-to-1” mapped elevator. If you want another one, you press another panel. I call this a “non-idempotent elevator”. This article only discusses the non-idempotent elevator scenario.

Individual selfishness causes collective delay

Based on historical statistical patterns, and modeling the “non-idempotent elevator” scenario with time-series programming, suppose working hours are 9:00 ~ 18:30. Then within 10 minutes of commuting critical points, for office buildings with floors <10, in my experience, taking the stairs is basically faster.

If there is only 1 person in the scenario, the strategy for choosing an elevator is actually very simple: choose “the nearest elevator moving in the same direction” as the optimal strategy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
type Work struct {
	Floor       int16     // working floor
	WorkHours   time.Time // work start time
	ClosingTime time.Time // work end time
}

// Person represents a person
type Person struct {
	Time        time.Time // time
	Floor       int16     // current floor
	TargetFloor int16     // target floor
	work        Work
}

func (p *Person) MVP(elevators []Elevator) (int, *Elevator) {
	t := p.Time
	if p.work.Floor < 10 && (t.Sub(p.work.ClosingTime).Abs() < 10*time.Minute || t.Sub(p.work.WorkHours).Abs() < 10*time.Minute) {
		//walking
		return -1, nil
	}
	if len(elevators) == 0 {
		return -1, nil
	}
	distance := time.Hour << 10
	var bestElevator Elevator
	var n int
	for k, e := range elevators {
		temp := *e.Status(t)
		if d := temp.Distance(p); d < distance {
			distance = d
			n = k
			bestElevator = temp
		}
	}
	// find and choose the nearest elevator
	return n, &bestElevator
}

However, in reality, cases like N people competing for 3 elevators are much more common. This strategy fails immediately under the N-person scenario.

Because “how many people are waiting for elevators in this building” is a black box for everyone not in the control room.

So many people choose the “all” strategy - pressing every button together, and even going up first then down after work. Even if no one presses in reverse order, if everyone presses all buttons after work, down-moving elevators will still stop at almost every floor.

Of course, some people may argue we can set an “FL” state: when an elevator is fully loaded, it goes straight down without stopping at any floor. But in a 4-people-4-elevators case, the problem is still obvious - 4 people are distributed on different floors, decision directions are completely random, and if everyone presses all 4 panels together, elevator resources are wasted to the greatest extent.

Non-idempotent elevators expose one fact: maximizing individual benefit harms collective benefit, and eventually harms one’s own payoff. Because taking elevators is meant to save as much time as possible, and the utility function is time. If everyone presses all buttons, it seems all elevators will come toward them, but in the end it still maximizes total elevator riding time.

The estate division problem in P=NP

A non-idempotent elevator represents the absolute conflict between collective interest and individual interest. Other than turning elevators into an “idempotent” model and letting the dispatch center coordinate, there seems to be no good solution. But if we directly quantify elevators as estate assets, and treat elevator allocation as the cake-cutting problem in P=NP (personally I prefer to call it the “estate division” problem), then the issue seems slightly simpler.

Let’s transform the problem: shrink N participants into a controllable number of “children”, and convert elevators into cash. Then all participants are no longer in a “black box” state relative to each other.

In my view, fair division (everyone believes they have received at least 1/n value of the cake) does not exist - suppose I am the family asset manager and have several children. For long-term asset growth, it is impossible to split all cash into equal N shares and hand one share to a son under 18.

Not to mention that when people look in the mirror, they tend to self-enhance (mere exposure effect). Rating oneself higher than objective facts is a common phenomenon. This cognitive bias, combined with objective constraints, makes it impossible to have an estate-division solution fair to everyone.

According to historical statistical experience, the final outcome of estate division still depends on each heir’s investment and wealth-management capability. Based on real financial returns and talent strengths, and through the test of time, a solution can finally emerge.

At this point, I finally understood the behavioral art of distributed courtship by Shoggoth: using the scumbag strategy of casting a wide net and catching more fish, to achieve multi-object differential learning gradient descent optimized for time efficiency.

Nearby advantage

A little closer to the bank, Where coins and notes are in the rank.

Идемпотентность - один из важных принципов проектирования программ.

Простейший пример: снятие наличных в ATM. Вы подтверждаете сумму и нажимаете “confirm”, после чего автомат начинает выдавать деньги. Но если в этот момент повторное нажатие “confirm” заставляет ATM продолжать выдачу, такой дизайн неидемпотентен.

Конечно, в реальности таких чудес не бывает. Период между нажатием confirm и получением денег в программировании относится к стадии “transaction lock”. В это время хоть 100 раз нажимай confirm - бесполезно.

Незаметно для нас ATM тоже стал видом потребительской электроники, которая скоро уйдет в прошлое. Но базовые принципы вроде идемпотентности и транзакций базы данных никуда не исчезли.

Неидемпотентный лифт

Например, недавно я столкнулся с видом “неидемпотентного лифта”. В традиционных коммерческих зданиях для удобства эксплуатации обычно настраивают модель “1 к N идемпотентности”: после нажатия кнопки вниз загораются все индикаторы вниз, а диспетчерский центр назначает ближайший лифт. Я называю это “идемпотентным лифтом”.

Неидемпотентный лифт отделяет кнопки вверх/вниз на панели от диспетчерского центра. Допустим, в здании стоят рядом 3 лифта. Нажатие вверх/вниз на одной панели управляет только тем лифтом, который связан с ней по схеме “1 к 1”. Нужен другой лифт - нажимаешь другую панель. Это я и называю “неидемпотентным лифтом”. В статье рассматривается только этот сценарий.

Индивидуальный эгоизм приводит к задержкам для группы

Если, опираясь на прошлые статистические закономерности, смоделировать сценарий “неидемпотентного лифта” через time-series programming и предположить рабочее время 9:00 ~ 18:30, то в 10-минутном окне вокруг пиков прихода/ухода, для офисных зданий с этажами <10, по моему опыту, по лестнице почти всегда быстрее.

Если же в сценарии только 1 человек, стратегия выбора лифта на практике очень проста: оптимально выбрать “ближайший к себе лифт в том же направлении”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
type Work struct {
	Floor       int16     // рабочий этаж
	WorkHours   time.Time // время начала работы
	ClosingTime time.Time // время окончания работы
}

// Person обозначает человека
type Person struct {
	Time        time.Time // время
	Floor       int16     // текущий этаж
	TargetFloor int16     // целевой этаж
	work        Work
}

func (p *Person) MVP(elevators []Elevator) (int, *Elevator) {
	t := p.Time
	if p.work.Floor < 10 && (t.Sub(p.work.ClosingTime).Abs() < 10*time.Minute || t.Sub(p.work.WorkHours).Abs() < 10*time.Minute) {
		// пешком
		return -1, nil
	}
	if len(elevators) == 0 {
		return -1, nil
	}
	distance := time.Hour << 10
	var bestElevator Elevator
	var n int
	for k, e := range elevators {
		temp := *e.Status(t)
		if d := temp.Distance(p); d < distance {
			distance = d
			n = k
			bestElevator = temp
		}
	}
	// найти и выбрать ближайший лифт
	return n, &bestElevator
}

Однако в реальности чаще встречается ситуация, когда N человек конкурируют за 3 лифта. В сценарии с N людьми эта стратегия сразу перестает работать.

Потому что “сколько людей ждут лифт в этом здании” - это black box для всех, кто не находится в диспетчерской.

Поэтому многие выбирают стратегию “all” - нажимают все кнопки сразу, а в час ухода с работы даже сначала вверх, потом вниз. Даже если никто не нажимает в обратном порядке, при нажатии всех кнопок всеми людьми в конце рабочего дня лифты, идущие вниз, останавливаются почти на каждом этаже.

Конечно, кто-то возразит: можно задать состояние “FL”, чтобы при полной загрузке лифт шел вниз без остановок. Но даже при 4 людях и 4 лифтах проблема остается очевидной - 4 человека распределены по разным этажам, направления решений полностью случайны, и если все нажимают все 4 панели сразу, ресурсы лифтов расходуются максимально неэффективно.

Неидемпотентный лифт вскрывает одну проблему: максимизация индивидуальной выгоды вредит коллективной выгоде и в конце концов снижает собственный результат. Потому что цель поездки на лифте - максимально экономить время, а функция полезности здесь - время. Если все нажимают все кнопки, на первый взгляд кажется, что все лифты поедут к тебе, но в итоге это все равно максимизирует время поездки.

Проблема раздела наследства в P=NP

Неидемпотентный лифт представляет абсолютное противоречие между интересами коллектива и интересами индивида. Кроме перевода лифтов в “идемпотентный” режим и координации через диспетчерский центр, хорошего решения, похоже, нет. Но если напрямую квантифицировать лифты как наследственное имущество, а распределение лифтов рассматривать как задачу деления торта в P=NP (лично я предпочитаю называть это задачей “раздела наследства”), тогда проблема выглядит чуть проще.

Переформулируем задачу: уменьшим N участников до управляемого числа “детей”, а лифты преобразуем в наличные. Тогда для всех участников друг друга уже не будет состояния “black box”.

На мой взгляд, справедливого распределения (когда каждый считает, что получил как минимум 1/n ценности торта) не существует - допустим, я управляющий семейными активами и у меня несколько детей. Ради долгосрочного роста активов невозможно просто разделить всю наличность на N равных частей и отдать одну сыну младше 18 лет.

Не говоря уже о том, что люди, глядя в зеркало, склонны к самоидеализации (mere exposure effect). Завышенная самооценка по сравнению с объективными фактами - распространенное явление. Это когнитивное искажение, плюс ограничения объективных условий, и приводят к тому, что у задачи раздела наследства не может быть решения, справедливого для всех.

Согласно историческому статистическому опыту, в итоге в задаче раздела наследства все равно решают уровень инвестиционно-финансовых навыков наследников. На основе реальной финансовой доходности и индивидуальных сильных сторон, проверенных временем, в конце концов появляется решение.

К этому моменту я наконец понял поведенческое искусство distributed courtship у 修格斯: через стратегию 渣男 вида 广撒网,多捞鱼 реализуется multi-object differential learning gradient descent, оптимизированный по эффективности времени.

Кто ближе, тот и первым

A little closer to the bank, Where coins and notes are in the rank.



💬 讨论 / Discussion

对这篇文章有想法?欢迎在 GitHub 上发起讨论。
Have thoughts on this post? Start a discussion on GitHub.

在 GitHub 参与讨论 / Discuss on GitHub