什么是幂等运算?


Answers:


964

在计算中,幂等运算是指如果使用相同的输入参数多次调用幂等运算,则不会产生任何其他影响。例如,从集合中删除项目可以视为对该集合的幂等操作。

在数学中,幂等运算是f(f(x))= f(x)的情况。例如,该abs()函数是幂等的,因为abs(abs(x)) = abs(x)对于x。

通过考虑数学定义中的x表示对象的状态,并且f是可以使该对象变异的运算,可以调和这些稍有不同的定义。例如,考虑Pythonset及其discard方法。该discard方法从集合中删除一个元素,如果该元素不存在,则不执行任何操作。所以:

my_set.discard(x)

与执行两次相同的操作具有完全相同的效果:

my_set.discard(x)
my_set.discard(x)

幂等操作通常用于网络协议的设计中,在该协议中,执行一项操作的请求至少会发生一次,但也可能会发生多次。如果该操作是幂等的,则两次执行此操作不会有任何危害。

有关更多信息,请参见有关幂等性的Wikipedia文章。


上面的答案以前有一些不正确和误导性的例子。以下注释是在2014年4月之前写的,是较旧的版本。


6
例子:因为上面的回答指出这Idempotent operations are often used in the design of network protocols是一个相关的例子,** GET不能改变服务器上的任何东西,所以GET是幂等的。在HTTP / Servlet上下文中,这意味着可以两次发出相同的请求,而不会产生负面影响。** POST不是幂等的。
— KNU

1
“无状态”是“幂等”的同义词吗?
— Michael Osofsky 2014年

2
@MichaelOsofsky:不,在set答案的Python 示例中,set对象显然具有状态,并且还提供了一些幂等操作,例如discard。
— Greg Hewgill 2014年

1
@MichaelOsofsky,discard也可以通过将状态包含在返回值中来以无状态方式实现:discard([my_set, x]) = [my_new_set, x]。这样就可以了discard(discard([my_set, x]))。请注意,[my_new_set, x]是只有一个参数,它的类型是2元组。
— Pacerier

2
@Green在阳ot 的情况下使用术语“ 相同的效果”时,表示结果相同,而不是操作。discard(x)第二次调用与第一次调用具有相同的效果:该集合将不再包含x。计算幂等性与系统的健壮性有关。由于事情可能会失败(例如,网络中断),因此当检测到故障时,如何恢复?最简单的恢复方法是再次执行此操作,但这仅在重新执行幂等时才有效。例如discard(x)是幂等的,但pop()不是。都是关于错误恢复的。
— Andreas

138

幂等运算可以重复任意次,其结果将与仅进行一次相同。在算术中,将零加到数字上是幂等的。

在“ RESTful” Web服务的上下文中讨论了幂等性。REST试图最大程度地利用HTTP来使程序访问Web内容,并且通常与基于SOAP的Web服务形成对比,后者只是在HTTP请求和响应中建立远程过程调用样式服务。

REST将Web应用程序组织为“资源”(例如Twitter用户或Flickr图像),然后使用POST,PUT,GET和DELETE的HTTP动词来创建,更新,读取和删除这些资源。

幂等在REST中扮演重要角色。如果您获取REST资源的表示形式(例如,从Flickr获取jpeg图像),而操作失败,则可以一次又一次地重复GET,直到操作成功。对于Web服务,获取图像的次数无关紧要。同样,如果您使用RESTful Web服务来更新您的Twitter帐户信息,则可以多次输入新信息,以便从Web服务获得确认。将其放置一千次与放置一次相同。同样,将REST资源删除一千次与删除一次相同。因此,幂等性使得构建可抵抗通信错误的Web服务变得容易得多。

进一步阅读:Richardson和Ruby 撰写的RESTful Web服务(在103-104页讨论了幂等性),以及Roy Fielding的REST博士学位论文。Fielding是HTTP 1.1 RFC-2616的作者之一,在第9.1.2节中讨论了幂等性。


清晰明了。然而,这不过只是一个幂等的解释。
— Pacerier

10
“幂等”是一个很重的单词,因为它听起来雄辩而又具有足够的字符以通过倍半方格检查。如果 本杰明·皮尔斯(Benjamin Peirce)选择了一个简单的用词,那么今天我们什至不会有这个问题。
— Pacerier,2015年

2
如何理解它:同样,将REST资源删除一千次与删除一次相同。如果资源已被删除,则无法再次删除。
— 2015年

1
@Green,但是您不会第一次删除它。您发送删除请求。重要的是您可以发送任意数量的请求。
— 卡雷斯(Caleth)'17

1
@JimFerrans我明白了。我认为可能有一些与功能相关的原因(内置在HTTP本身中),为什么可以重新发送PUT而不必担心POST,而不必担心。现在看来,我们只是被要求遵守HTTP标准,并且其行为完全基于服务器的实现方式
— mangusta

109

无论您调用该操作多少次,结果都是一样的。


8
我听说过幂等定义为以下任何一个或两个:1)对于给定的一组输入,它将始终返回相同的输出。2)不产生任何副作用。我的问题是,如果某个函数符合#1,但不符合#2,因为它会导致与计算无关的副作用(例如,将请求记录到数据存储中),是否仍然认为幂等?
— 基思·贝内特

12
调用操作的结果必须包括系统的状态,因此,如果操作具有某种累积的副作用,则它不是幂等的。但是,如果无论调用多少次,副作用都使系统保持相同状态,则可能是幂等的。
— 罗伯特

4
简短而可爱,我喜欢这种答案。不知道为什么我必须经常检查这个术语,这是一个不陪我的日子。
— Prancer

1
@KeithBennett,第二个定义是错误的。“无副作用”并不意味着幂等。幂等函数会产生副作用。例如MySQL truncate和delete。
— Pacerier,2015年

结果将是相同的(即系统状态),但是响应可能会有所不同(即REST服务上的HTTP状态代码)。
— G. Steigert

50

幂等是指一次执行一项操作或多次执行一项操作具有相同的效果。

例子:

  • 乘以零。无论您执行多少次,结果仍然为零。
  • 设置一个布尔标志。无论您执行多少次,该标志都会保持设置状态。
  • 从具有给定ID的数据库中删除一行。如果再次尝试,该行仍然不存在。

对于纯函数(没有副作用的函数),幂等性意味着f(x)= f(f(x))= f(f(f(x()))= f(f(f(f(x)))) )= ......对于x的所有值

对于具有副作用的功能,幂等性还意味着在首次应用后不会引起其他副作用。如果愿意,可以将世界状况视为该函数的附加“隐藏”参数。

请注意,在一个同时进行并行操作的世界中,您可能会发现原来认为是幂等的操作不再如此(例如,在上面的示例中,另一个线程可能会取消设置布尔值的值)。基本上,只要您具有并发性和可变状态,就需要对幂等性进行更仔细的考虑。

幂等性通常是构建健壮系统的有用属性。例如,如果存在从第三方接收重复消息的风险,则使消息处理程序充当幂等操作会很有帮助,这样消息效果只会发生一次。


1
如果是纯函数f(x) = f(f(x)),那f(x){return x+1;}是不是纯函数?因为f(x) != f(f(x)):f(1)给2同时f(2)给出了3
— Pacerier

1
@Pacerier不,@ mikera说的是纯净和幂等的含义f(x) = f(f(x))。但是正如@GregHewgill所提到的,为了使此定义有意义,您必须考虑x将其视为对象以及f使对象状态发生变化的操作(即:的输出f是mutated x)。
— 贾斯汀·J·史塔克


16

只是想抛出一个证明幂等的真实用例。在JavaScript中,假设您正在定义一堆模型类(如在MVC模型中)。通常实现的方式在功能上等效于以下示例(基本示例):

function model(name) {
  function Model() {
    this.name = name;
  }

  return Model;
}

然后,您可以像这样定义新的类:

var User = model('user');
var Article = model('article');

但是,如果您尝试从代码中的其他位置User通过获取类model('user'),则它将失败:

var User = model('user');
// ... then somewhere else in the code (in a different scope)
var User = model('user');

这两个User构造函数将不同。那是,

model('user') !== model('user');

为了使其幂等,您只需添加某种缓存机制,如下所示:

var collection = {};

function model(name) {
  if (collection[name])
    return collection[name];

  function Model() {
    this.name = name;
  }

  collection[name] = Model;
  return Model;
}

通过添加缓存,您每次执行的操作都model('user')将是同一个对象,因此是幂等的。所以:

model('user') === model('user');

10

幂等操作是可以多次应用的操作,动作或请求,而不会改变结果(即系统状态),超出了最初的应用程序。

示例(Web应用程序上下文):

决定因素:发出多个相同的请求与发出单个请求具有相同的效果。电子邮件消息系统中的一条消息已打开,并在数据库中标记为“已打开”。一个人可以多次打开该消息,但是重复执行此操作只会导致该消息处于“打开”状态。这是一个幂等操作。第一次使用与资源不匹配的信息(系统状态)PUT对资源进行更新时,系统状态将随着资源更新而改变。如果一个PUT反复对资源进行相同的更新,则更新中的信息将与每个PUT上已存在于系统中的信息相匹配,并且不会更改系统状态。具有相同信息的重复PUT是幂等的:

非强制性:如果某个操作总是引起状态变化,例如一次又一次地向用户发布同一条消息,导致每次都发送新消息并将其存储在数据库中,那么我们就说该操作是非强制性的。

NULLIPOTENT:如果某个操作没有副作用,例如仅在网页上显示信息而数据库中没有任何更改(换句话说,您仅在读取数据库),则说该操作为NULLIPOTENT。所有GET均应无效。

在谈论系统状态时,我们显然忽略了希望的无害和不可避免的影响,例如日志记录和诊断。


9

幂等运算:如果多次执行,则没有副作用。
示例:一种从数据资源中检索值并进行打印的

操作非等幂操作:如果多次执行该操作会造成一定危害。(当它们更改某些值或状态时)
示例:从银行帐户中提取的操作


3
其实是错误的答案!对于幂等运算说“没有副作用”是不对的。对于非幂等运算来说,“造成一些伤害”是一个令人困惑的答案。
— Saeed Mohtasham

9

相当详细和技术性的答案。只需添加一个简单的定义。

幂等=可重新运行

例如,Create如果执行多次,则 操作本身无法保证不会出错。但是,如果有操作,CreateOrUpdate那么它将声明可重新运行性(幂等)。


3
这是一个欺骗性的定义。可重新运行性不能保证是幂等的。某个操作可以重新运行,并且在每次运行中都可以为结果添加其他效果,因此不会成为幂等。
— Saeed Mohtasham

7

一个集合上的幂等运算在被应用一次或多次后,其成员保持不变。

它可以是绝对值(x)之类的一元运算,其中x属于一组正整数。这里的absolute(absolute(x))= x。

它可以是二进制运算,就像集合与自身的并集将始终返回同一集合一样。

干杯


幂等运算是f(f(x))= f(x)的运算。“让成员保持不变”不是正确的答案。
— Saeed Mohtasham

7

任何第n个结果都将导致输出与第一个结果的值匹配的任何操作。例如,-1的绝对值为1。-1的绝对值的绝对值为1。-1的绝对值的绝对值的绝对值为1。依此类推。

另请参阅:什么时候使用递归真的很愚蠢?


1
即使十年后,这也是一个精妙的答案。+1
— snr

2

理解幂等操作的一个很好的例子可能是用遥控钥匙锁定汽车。

log(Car.state) // unlocked

Remote.lock();
log(Car.state) // locked

Remote.lock();
Remote.lock();
Remote.lock();
log(Car.state) // locked

lock是幂等运算。即使每次运行都有一些副作用lock(例如闪烁),无论您进行多少次锁定操作,汽车仍处于相同的锁定状态。


1

我的5c:在集成和网络中,幂等性非常重要。现实生活中的几个例子:想象一下,我们将数据传递到目标系统。通过一系列消息传递的数据。1.如果序列在通道中混合会发生什么?(因为网络软件包总是这样做:))。如果目标系统是幂等的,结果将不会有所不同。如果目标系统依赖于顺序中的正确顺序,则我们必须在目标站点上实现重新排序器,这将恢复正确的顺序。2.如果消息重复,该怎么办?如果目标系统的通道未及时确认,则源系统(或通道本身)通常会发送该消息的另一个副本。结果,我们可以在目标系统侧获得重复的消息。如果目标系统是幂等的,它会照顾好它,结果不会有所不同。如果目标系统不是幂等的,则必须在通道的目标系统侧实现重复数据删除器。


与其他任何请求(或其他任何会改变系统状态的事件)隔离发送的单个请求的幂等性与对请求进行重新排序不同。HTTP PUT请求和HTTP DELETE请求都应分别幂等,但这并不意味着在同一URL上调用PUT和DELETE的顺序无关紧要,因为PUT请求可能会有副作用!
— 罗宾·格林

1

简而言之,幂等运算意味着无论您操作幂等运算多少次,该操作都不会导致不同的结果。

例如,根据HTTP规范的定义,GET, HEAD, PUT, and DELETE是幂等运算;但是POST and PATCH不是。因此,有时会POST被替换PUT。


-4

重试安全。

通常是了解其在计算机科学中含义的最简单方法。


1
重试意味着第一次或上次失败。不太一样。
— Lasse V. Karlsen

谁编辑了我的问题并让我投了反对票?那不是我发布的文字吗?
— teknopaul

您可以通过单击答案下方的“ X个小时前编辑过”或类似内容的链接来检查编辑日志。
— Lasse V. Karlsen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.