什么是幂等运算?

什么是幂等运算?

347375 次浏览

无论调用该操作多少次,结果都是相同的。

在计算中,幂等运算是指如果使用相同的输入参数多次调用它,则不会产生额外影响的运算。例如,从集合中移除一项可以被认为是集合上的幂等操作。

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

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

my_set.discard(x)

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

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

幂等操作经常用于网络协议的设计中,其中执行操作的请求保证至少发生一次,但也可能发生多次。如果操作是幂等的,那么执行两次或两次以上的操作是没有伤害的。

更多信息请参见维基百科文章幂等性


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

幂等运算即使调用多次也会产生相同状态的结果,前提是传入相同的参数。

任何操作,每n个结果都会产生与第1个结果值匹配的输出。例如,-1的绝对值是1。-1的绝对值的绝对值是1。-1绝对值的绝对值的绝对值等于1。等等。# 0

对集合的幂等运算在应用一次或多次时,其成员保持不变。

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

它可以是一个二进制操作,比如集合与其自身的并集总是返回相同的集合。

干杯

幂等运算可以重复任意次数,结果与只做一次是一样的。在算术中,一个数加零是幂等的。

幂等性在“RESTful”web服务的上下文中被讨论了很多。REST寻求最大限度地利用HTTP来为程序提供对web内容的访问,并且通常与基于soap的web服务进行设置,后者只是在HTTP请求和响应中隐藏远程过程调用样式的服务。

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

幂等性在REST中扮演着重要的角色。如果您获取一个REST资源的表示(例如,从Flickr获取一个jpeg图像),而操作失败了,您可以一次又一次地重复GET,直到操作成功。对于web服务,图像被获取多少次并不重要。同样,如果您使用基于rest的web服务来更新Twitter帐户信息,您可以尽可能多次地PUT新信息,以便从web服务获得确认。放一千次和放一次是一样的。类似地,删除一个REST资源一千次与删除一次是一样的。因此,幂等性使得构建一个对通信错误具有弹性的web服务变得容易得多。

进一步阅读:理查德森和鲁比的rest式Web服务(在103-104页讨论了幂等性),以及罗伊·菲尔丁的REST博士论文。Fielding是HTTP 1.1 RFC-2616的作者之一,RFC-2616在第2条中讨论了幂等性。

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

例子:

  • 乘以0。无论你做多少次,结果仍然是零。
  • 设置布尔标志。不管你做了多少次,旗帜都不会动摇。
  • 从数据库中删除具有给定ID的行。如果你再试一次,排还是消失了。

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

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

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

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

幂等操作:多次执行无副作用的操作。
例子:从数据资源中检索值并打印它的操作

非幂等性操作:多次执行会造成伤害的操作。(当它们改变某些值或状态时)
示例:从银行账户提现的操作

只是想提出一个真实的用例来证明幂等性。在JavaScript中,假设你定义了一堆模型类(就像MVC模型一样)。它的实现方式通常是这样的(基本示例):

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

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

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

但是如果你试图通过model('user')从代码中的其他地方获得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');
< p > 5 c:在积分和网络中,幂等性是非常重要的。以下是一些现实生活中的例子:想象一下,我们向目标系统交付数据。由消息序列传递的数据。1. 如果序列在信道中混合会发生什么?(网络包总是这样:))。如果目标系统是幂等的,结果不会不同。如果目标系统依赖于序列中的正确顺序,我们必须在目标站点上实现resequencer,这将恢复正确的顺序。2. 如果消息重复会发生什么?如果目标系统的通道没有及时确认,源系统(或通道本身)通常会发送另一份消息副本。因此,我们可以在目标系统端有重复的消息。如果目标系统是幂等的,它会处理它,结果不会有什么不同。如果目标系统不是幂等的,我们必须在通道的目标系统端实现重复数据删除器

幂等操作是一种可以应用多次而不改变结果(即系统状态)的操作、动作或请求,超出初始应用。

示例(web应用上下文):

< p >幂等:发出多个相同的请求与发出单个请求具有相同的效果。电子邮件消息系统中的消息被打开,并在数据库中标记为“已打开”。可以多次打开该消息,但这种重复操作只会导致该消息处于“已打开”状态。这是一个幂等运算。当第一次使用与资源(系统状态)不匹配的信息对资源进行更新时,系统状态将随着资源的更新而改变。如果重复对资源进行相同的更新,则更新中的信息将在每次PUT时与系统中已经存在的信息相匹配,系统状态不会发生变化。具有相同信息的重复PUT是幂等的:第一个PUT可能会改变系统的状态,随后的PUT则不会。< / p > < p >非幂等性:如果一个操作总是导致状态的变化,比如反复向用户发送相同的消息,导致每次都发送新消息并存储在数据库中,我们称该操作为NON-IDEMPOTENT < p > NULLIPOTENT:如果一个操作没有副作用,就像仅仅在网页上显示信息而没有对数据库进行任何更改(换句话说,你只是在读取数据库),我们说这个操作是NULLIPOTENT。所有get都应该是无效的。< / p >

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

相当详细和专业的回答。只是添加了一个简单的定义。

幂等=可重复运行

例如,< p >Create操作本身如果执行多次,则不能保证运行时没有错误。但是如果有一个操作CreateOrUpdate,那么它表示可重运行性(等幂)

简而言之,幂等运算意味着无论你做多少次幂等运算都不会得到不同的结果。

例如,根据HTTP规范的定义,GET, HEAD, PUT, and DELETE是幂等操作;然而,第一条不是。这就是为什么有时POST会被PUT取代。

理解幂等运算的一个好例子可能是用远程钥匙锁汽车。

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

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

如果一个操作执行多次等同于执行一次,那么它就是幂等的。

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

0:音量增加1。如果一个进程执行该操作50次,结束时的卷将为初始体积+ 50;如果一个进程执行该操作100次,结束时的卷将为初始体积+ 100。正如您可以清楚地看到的,最终结果根据执行操作的次数而变化。因此,我们可以得出结论,这个运算是第三次幂等的。

我在大胆的中突出显示了最终结果。


如果从编程的角度考虑,假设我有一个操作,其中函数ffoo作为输入,而f的输出被设置为foo。如果在进程结束时(执行该操作50/100次或更多次),我的foo变量保存的值是该操作只执行一次时的值,那么该操作是幂等的,否则为NOT。

# 0

# 0 # 1

如果f返回输入的平方,那么操作是幂等的。因为0在最后会是1

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


在数学意义上,幂等性的含义略有不同:
# 0
这里f(x)的输出再次作为输入传递给f,这在编程中并不需要总是这样

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

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

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

我们应该使用idempotent tokens。当客户端向服务发送请求时,它应该有某种类型的请求id,可以保存在DB中,以显示我们已经执行了请求。如果客户端重试请求,“;InstanceB"将检查requesttid。由于特定的请求已经被执行,因此它不会对DB项进行任何更改。这类请求被称为idempotent requests。因此,我们多次发送相同的请求,但不会做任何更改