什么是幂等操作?

What is an idempotent operation?

提问人:Will 提问时间:7/3/2009 最后编辑:shA.tWill 更新时间:6/11/2023 访问量:368254

问:

什么是幂等操作?

与语言无关 的定义 幂等

评论

1赞 Qiulang 12/23/2022
查看此故事,了解由幂等操作 threadreaderapp.com/thread/1502947315279187979.html 引起的最新事件(2022 年)

答:

150赞 Robert 7/3/2009 #1

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

评论

8赞 Keith Bennett 6/29/2012
我听说过幂等定义为以下任一或两种:1)对于一组给定的输入,它将始终返回相同的输出。2)不产生任何副作用。我的问题是,如果一个函数符合 #1,但不符合 #2,因为它会导致与计算无关的副作用(例如,将请求记录到数据存储),它是否仍然被认为是幂等的?
13赞 Robert 7/18/2012
调用操作的结果必须包含系统的状态,因此,如果操作具有一些累积的副作用,则它不是幂等的;但是,如果无论调用多少次操作,副作用都会使系统处于相同的状态,那么它可能是幂等的。
9赞 Prancer 2/2/2015
短小精悍,我喜欢这样的回答。不知道为什么我必须不断地查找这个词,它只是一个不会留在我身边的术语。
1赞 Pacerier 3/11/2015
@KeithBennett,第二个定义是错误的。“无副作用”并不意味着幂等。幂等函数可能会产生副作用。例如 MySQL 和 .truncatedelete
1赞 swcraft 4/27/2020
因此,如果数据库中有一个行计数器,用于检查请求输入与数据库状态的数据完整性,那么是否需要在幂等定义中考虑该行计数器?该行计数器将针对每个请求增加,但不会作为结果的一部分返回。
1280赞 Greg Hewgill 7/3/2009 #2

在计算中,幂等操作是指使用相同的输入参数多次调用幂等操作时不会产生额外效果的操作。例如,从集合中删除项可被视为对集合的幂等操作。

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

这些略有不同的定义可以通过考虑数学定义中的 x 表示对象的状态来调和,而 f 是可能改变该对象的操作。例如,考虑 Python 及其方法。该方法从集合中删除元素,如果该元素不存在,则不执行任何操作。所以:discarddiscard

my_set.discard(x)

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

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

幂等操作通常用于网络协议的设计中,其中执行操作的请求保证至少发生一次,但也可能发生多次。如果操作是幂等的,则执行两次或更多次操作没有坏处。

有关更多信息,请参阅维基百科上关于幂等性的文章。


上面的答案之前有一些不正确和误导性的例子。以下 2014 年 4 月之前撰写的评论是指较早的修订版。

评论

24赞 KNU 4/1/2014
示例:由于上面的答案指出这是一个相关的示例,因此 GET 不应该更改服务器上的任何内容,因此 GET 是幂等的。在 HTTP/servlet 上下文中,这意味着相同的请求可以发出两次而不会产生负面影响。**POST 不是幂等的。Idempotent operations are often used in the design of network protocols
4赞 Michael Osofsky 12/6/2014
“无状态”是“幂等”的同义词吗?
4赞 Greg Hewgill 12/8/2014
@MichaelOsofsky:不,在答案的 Python 示例中,set 对象显然具有状态,并且还提供了一些幂等操作,例如 .setdiscard
2赞 Pacerier 3/11/2015
@MichaelOsofsky,也可以通过在返回值中包含状态来以无状态方式实现:。所以你可以做.请注意,这只是一个参数,其类型为 2 元组。discarddiscard([my_set, x]) = [my_new_set, x]discard(discard([my_set, x]))[my_new_set, x]
9赞 Andreas 4/27/2016
@Green 在阳痿的背景下使用“相同效果”一词时,这意味着结果是相同的,而不是动作。第二次调用将与第一次调用具有相同的效果:集合将不再包含 。计算幂等性是关于系统的鲁棒性。由于事情可能会发生故障(例如网络中断),当检测到故障时,如何恢复?最简单的恢复是再做一次,但这只有在再次做幂等的情况下才有效。例如 是幂等的,但不是。这一切都与错误恢复有关。discard(x)xdiscard(x)pop()
30赞 Caleb Huitt - cjhuitt 7/3/2009 #3

幂等操作以相同的状态生成结果,即使多次调用它,前提是您传入相同的参数。

评论

1赞 Green 10/10/2015
听起来一点也不合逻辑。stackoverflow.com/questions/1077412/......
3赞 Suncat2000 4/13/2018
我认为您可能会混淆幂等确定性
10赞 Oorang 7/3/2009 #4

每 n 个结果都会产生与第一个结果的值匹配的输出。例如,-1 的绝对值为 1。-1 的绝对值的绝对值为 1。-1的绝对值的绝对值的绝对值为1。等等。

Смотритетакже: 什么时候使用递归是真正愚蠢的时机?

8赞 Arnkrishn 7/3/2009 #5

对集合的幂等操作在应用一次或多次时使其成员保持不变。

它可以是像 absolute(x) 这样的一元运算,其中 x 属于一组正整数。这里 absolute(absolute(x)) = x。

它可以是一个二进制操作,例如集合与自身的并集将始终返回相同的集合。

干杯

评论

2赞 Saeed Mohtasham 4/16/2018
幂等运算是 f(f(x)) = f(x) 的运算。“保持其成员不变”不是一个正确的答案。
178赞 Jim Ferrans 7/3/2009 #6

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

幂等性在“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 Services(幂等性在第 103-104 页讨论),以及 Roy Fielding 关于 REST 的博士论文。Fielding 是 HTTP 1.1 RFC-2616 的作者之一,该书在第 9.1.2 节中讨论了幂等性。

评论

21赞 Pacerier 3/11/2015
“幂等性”是一个重载的词,因为它听起来很夸张,并且有足够的字符来通过 sesquipedalian 检查。如果本杰明·皮尔斯(Benjamin Peirce)选择了一个听起来更简单的词,我们今天甚至不会有这个问题。
3赞 Green 10/10/2015
如何理解:同样,删除REST资源一千次与删除一次相同?如果资源已被删除,则无法再次删除该资源。
3赞 Caleth 4/6/2017
@Green但您不会在第一次删除它。发送删除请求。重要的一点是,您可以根据需要发送任意数量的请求。
2赞 mangusta 2/22/2020
@JimFerrans我明白了。我认为可能有一些与功能相关的原因(内置于HTTP本身中),为什么PUT可以毫无顾虑地重新发送,而POST则不能。现在看来,我们只是被要求遵守HTTP标准,并且行为完全基于服务器的实现方式
1赞 dret 11/19/2021
“在算术中,将零加到数字上是幂等的。”这是一个不好的例子,因为添加零不会改变任何事情。幂等意味着它(可能)改变事物,但无论应用一次还是多次,都以相同的方式改变。上面进一步给出的 abs() 函数是一个更好的例子。
64赞 mikera 3/5/2012 #7

幂等性意味着应用一次操作或多次应用操作具有相同的效果。

例子:

  • 乘以零。不管你做多少次,结果仍然是零。
  • 设置布尔标志。无论您这样做多少次,旗帜都会保持设置状态。
  • 从具有给定 ID 的数据库中删除行。如果再试一次,该行仍然不见了。

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

对于具有副作用的功能,幂等性进一步意味着在第一次应用后不会引起额外的副作用。如果您愿意,可以将世界状态视为函数的附加“隐藏”参数。

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

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

评论

1赞 Pacerier 3/11/2015
如果对于纯函数,你是说那不是纯函数吗?因为:给 2 而给 3。f(x) = f(f(x))f(x){return x+1;}f(x) != f(f(x))f(1)f(2)
4赞 Justin J Stark 10/18/2016
@Pacerier 不,@mikera说纯粹幂等意味着.但正如@GregHewgill提到的,为了使这个定义有意义,你必须考虑作为一个对象和一个改变对象状态的操作(即:的输出是一个突变的)。f(x) = f(f(x))xffx
10赞 Mahmoud Abou-Eita 12/6/2012 #8

幂等操作:如果多次执行,则不会产生副作用的操作。
示例:从数据资源中检索值并打印该

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

评论

6赞 Saeed Mohtasham 4/16/2018
其实是一个错误的答案!对于幂等操作来说,“没有副作用”是不对的。对于非幂等操作来说,说“造成一些伤害”是一个令人困惑的答案。
18赞 Lance 10/9/2013 #9

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

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

  return Model;
}

然后,您可以定义如下新类:

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

但是,如果您尝试从代码中的其他位置通过 获取类,它将失败:Usermodel('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');

评论

1赞 Ash 7/2/2020
这个答案似乎不对。幂等性是指在给定输入参数的情况下调用您希望更改某些状态的操作,如果随后使用相同的参数再次调用该操作,则不会对状态产生进一步影响。但是在您的示例中,甚至在使用缓存之前,如果我们调用 model('user') 两次,这已经是幂等的,没有状态更改,只是创建并将一个新的不同对象返回给调用者(未存储)。您描述的是一种对象标识工厂模式,该模式确保在调用之间返回“相同”对象,这很有用,但不能解释幂等性。
1赞 Leonid Ganeline 11/8/2013 #10

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

评论

0赞 Robin Green 3/8/2016
与任何其他请求(或更改系统状态的任何其他事件)隔离发送的单个请求的幂等性与重新排序请求不同。HTTP PUT请求和HTTP DELETE请求都应该是单独幂等的 - 但这并不意味着在同一个URL上调用PUT和DELETE的顺序无关紧要,因为PUT请求可能会产生副作用!
21赞 nmit026 8/4/2015 #11

幂等操作是一种操作、操作或请求,可以在初始应用之后多次应用,而不会更改结果,即系统状态。

示例(WEB 应用上下文):

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

无同位: 如果一个操作总是导致状态发生变化,比如一遍又一遍地将相同的消息 POST 给用户,导致每次都发送一条新消息并存储在数据库中,我们说该操作是非 IDEMPOTENT。

无能性: 如果一个操作没有副作用,比如纯粹在网页上显示信息而不对数据库进行任何更改(换句话说,你只是在读取数据库),我们说该操作是无效的。所有 GET 都应该是无能的。

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

11赞 Manish Basantani 8/13/2015 #12

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

幂等 = 可重复运行

例如,如果多次执行,则不能保证操作本身不会出错。 但是,如果有操作,则它声明可重新运行(幂等性)。CreateCreateOrUpdate

评论

5赞 Saeed Mohtasham 4/16/2018
这是一个欺骗性的定义。可重运行性不保证是幂等的。操作可以重新运行,并且在每次运行中,它都可以向结果添加其他效果,因此它不是幂等的。
5赞 Marcus Thornton 3/25/2016 #13

简而言之,幂等操作意味着无论操作幂等操作多少次,该操作都不会产生不同的结果。

例如,根据HTTP规范的定义,是幂等操作;然而,事实并非如此。这就是为什么有时被 .GET, HEAD, PUT, and DELETEPOST and PATCHPOSTPUT

39赞 IVN 9/18/2019 #14

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

log(Car.state) // unlocked

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

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

lock是幂等操作。即使每次跑步时都有一些副作用,比如眨眼,但汽车仍然处于相同的锁定状态,无论你运行多少次锁定操作。lock

评论

2赞 Stobor 5/13/2022
一个好主意是将其与一些遥控器进行对比,这些遥控器不是两个按钮和 ,而是一个按钮。在这种情况下,单击按钮不是幂等的 - 每次单击最终都会更改状态,在 和 之间交替。lock()unlock()toggleLock()unlockedlocked
4赞 Aman Godara 1/12/2022 #15

如果多次执行操作等同于执行一次,则称其为幂等操作。

例如:将音量设置为 20。 无论电视的音量设置为 20 多少次,最终结果都是音量为 20。即使一个进程执行操作 50/100 次或更多次,在进程结束时,卷也将为 20。

反例:将音量增加 1。如果进程执行此操作 50 次,则结束卷将为初始卷 + 50,如果进程执行操作 100 次,则结束卷将为初始卷 + 100。您可以清楚地看到,最终结果会根据操作的执行次数而有所不同。因此,我们可以得出结论,此操作不是幂等的。

我用粗体突出显示了最终结果。


如果你从编程的角度来考虑,假设我有一个操作,其中一个函数作为输入,而输出设置为back。如果在进程结束时(执行此操作 50/100 次或更多次),我的变量保存操作仅执行一次时的值,则该操作是幂等的,否则不是。ffooffoofoo

foo = <some random value here, let's say -2>

{ foo = f( foo ) }   大括号勾勒出操作的轮廓

如果 f 返回输入的平方,则操作不是幂等的。因为最后会foo(-2) raised to the power (number of times operation is executed)

如果 f 返回输入的绝对值,则该操作是幂等的,因为无论执行多少次操作,该操作都将是 。
在这里,最终结果定义为变量的最终值。
fooabs(-2)foo


在数学意义上,幂等性的含义略有不同:

这里的输出作为输入传递给 Again,编程并不总是如此。
f(f(....f(x))) = f(x)f(x)f

评论

0赞 Aman Godara 1/12/2022
参考资料: ttboj.wordpress.com/2017/05/05/...
0赞 Abimael Domínguez 4/20/2022 #16

对于工作流管理器(如 Apache Airflow),如果管道中的幂等性操作失败,系统可以自动重试任务,而不会影响系统。即使日志发生了变化,这也很好,因为你可以看到事件。

在这种情况下,最重要的是您的系统可以重试失败的任务,并且不会弄乱管道(例如,每次重试都会在表中附加相同的数据)

评论

0赞 Dendi Handian 7/21/2022
但只需在上述内容之前先解释一下“幂等操作”。
0赞 Yilmaz 9/5/2022 #17

假设客户端向“IstanceA”服务发出请求,该服务处理该请求,将其传递给数据库,并在发送响应之前关闭。因为客户端没有看到它已被处理,它将重试相同的请求。负载均衡器会将请求转发到另一个服务实例“InstanceB”,该实例将对同一数据库项进行相同的更改。

我们应该使用 .当客户端向服务发送请求时,它应该有某种可以保存在数据库中的 request-id,以表明我们已经执行了请求。如果客户端重试请求,“InstanceB”将检查 requestId。由于该特定请求已执行,因此它不会对数据库项进行任何更改。这些类型的请求称为 。因此,我们会多次发送相同的请求,但不会进行任何更改idempotent tokensidempotent requests

1赞 Monis 6/11/2023 #18

1. 幂等性基础

在数学上,如果 . 因此,如果我们有一个函数,它返回整数的正对应物;则必须满足以下条件:f(f(x)) = f(x)absolute(x)x

absolute(absolute(x)) = absolute(x)

如果我们把 x 作为 ,无论我们重复这个操作多少次,第一次执行后的结果和第一次执行后的结果都是完全一样的。-100

所以

absolute(-100) = 100
AND
absolute(absolute(-100)) = absolute(100) = 100
=> absolute(absolute(x)) = absolute(x)

❗ 这里需要注意的重要一点是,“结果”并不一定意味着从函数返回的数据。它是指正在执行操作的数据。

因此,如果你在面向对象编程中采用一个函数,例如,一个带有值的集合,你尝试做;结果,即集合的内容不会改变。无论您重复此操作多少次,结果都将始终相同,即 .但是,当您添加一个集合中不存在的元素时,即您执行一个集合变为(不考虑顺序)。但是当你再次重复操作(甚至 100 次)时,结果(即集合)将继续包含 .对于列表,情况并非如此,因为它可以包含重复项。每次向列表添加内容时,它都会被添加。{1,2,4}add(2){1,2,4}add(3){1,2,4,3}{1,2,4,3}

为简化起见,

如果一个操作可以多次重复,使第一次执行后的结果和 n 次执行后的结果完全相同,则该操作被称为幂等。

除此之外,任何不更改数据的操作都是幂等的,因为它对数据的状态没有任何影响。

2. REST 中的幂等性 因此,像(不更改数据)这样的请求方法是幂等的(前提是它们被正确实现)。 对于打算更改数据的方法,它们的幂等性可能会有所不同。例如:GET, HEAD, OPTIONS, TRACE..

  • PUT & DELETE:应该以幂等的方式实现。
  • POST 和 PATCH:不保证是幂等的。他们可能是,也可能不是。

3. 为什么 PUT 必须是幂等的?

根据 IETF 的 RFC-7231,旨在替换服务器的状态。因此,如果您在网站上存储了一个地址,则 PUT 请求的请求中应包含整个地址。此外,它应该替换服务器上的数据(如果尚不存在,则创建)。因此,第一次执行请求后的 RESULT 和多次执行同一请求后的结果完全相同。PUT

4. 为什么 DELETE 必须是幂等的?

Delete 用于删除服务器上的资源。因此,如果您要删除地址,则无法再次删除同一地址(该地址不存在,也不会删除任何进一步的地址)。因此,第一次执行后的 RESULT 和多次执行同一请求后的 RESULT 完全相同。

❗ REST中一个常见的误解是,如果请求每次执行时都收到相同的响应,那么它就是幂等的。这是不正确的。结果始终与服务器上的数据(即对其执行操作的数据)相关。在考虑REST中的幂等性时,请考虑服务器的状态。

此视频非常详细地解释了这些概念: https://www.youtube.com/watch?v=R7s2FVN4c9Q