提问人:Will 提问时间:7/3/2009 最后编辑:shA.tWill 更新时间:6/11/2023 访问量:368254
什么是幂等操作?
What is an idempotent operation?
答:
无论调用多少次操作,结果都是一样的。
评论
truncate
delete
在计算中,幂等操作是指使用相同的输入参数多次调用幂等操作时不会产生额外效果的操作。例如,从集合中删除项可被视为对集合的幂等操作。
在数学中,幂等运算是 f(f(x)) = f(x) 的运算。例如,该函数是幂等的,因为对于所有 .abs()
abs(abs(x)) = abs(x)
x
这些略有不同的定义可以通过考虑数学定义中的 x 表示对象的状态来调和,而 f 是可能改变该对象的操作。例如,考虑 Python 集
及其方法。该方法从集合中删除元素,如果该元素不存在,则不执行任何操作。所以:discard
discard
my_set.discard(x)
与执行两次相同的操作具有完全相同的效果:
my_set.discard(x)
my_set.discard(x)
幂等操作通常用于网络协议的设计中,其中执行操作的请求保证至少发生一次,但也可能发生多次。如果操作是幂等的,则执行两次或更多次操作没有坏处。
有关更多信息,请参阅维基百科上关于幂等性的文章。
上面的答案之前有一些不正确和误导性的例子。以下 2014 年 4 月之前撰写的评论是指较早的修订版。
评论
Idempotent operations are often used in the design of network protocols
set
discard
discard
discard([my_set, x]) = [my_new_set, x]
discard(discard([my_set, x]))
[my_new_set, x]
discard(x)
x
discard(x)
pop()
幂等操作以相同的状态生成结果,即使多次调用它,前提是您传入相同的参数。
评论
每 n 个结果都会产生与第一个结果的值匹配的输出。例如,-1 的绝对值为 1。-1 的绝对值的绝对值为 1。-1的绝对值的绝对值的绝对值为1。等等。
Смотритетакже: 什么时候使用递归是真正愚蠢的时机?
对集合的幂等操作在应用一次或多次时使其成员保持不变。
它可以是像 absolute(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 服务来说,图像被获取多少次并不重要。同样,如果您使用 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 节中讨论了幂等性。
评论
幂等性意味着应用一次操作或多次应用操作具有相同的效果。
例子:
- 乘以零。不管你做多少次,结果仍然是零。
- 设置布尔标志。无论您这样做多少次,旗帜都会保持设置状态。
- 从具有给定 ID 的数据库中删除行。如果再试一次,该行仍然不见了。
对于纯函数(没有副作用的函数),幂等性意味着 f(x) = f(f(x)) = f(f(f(x))) = f(f(f(f(x)))) = ......对于 x 的所有值
对于具有副作用的功能,幂等性进一步意味着在第一次应用后不会引起额外的副作用。如果您愿意,可以将世界状态视为函数的附加“隐藏”参数。
请注意,在进行并发操作的世界中,您可能会发现您认为是幂等的操作不再如此(例如,在上面的示例中,另一个线程可以取消设置布尔标志的值)。基本上,每当你有并发和可变状态时,你都需要更仔细地考虑幂等性。
幂等性通常是构建健壮系统的有用属性。例如,如果存在可能从第三方收到重复消息的风险,则让消息处理程序充当幂等操作会很有帮助,这样消息效果就会只发生一次。
评论
f(x) = f(f(x))
f(x){return x+1;}
f(x) != f(f(x))
f(1)
f(2)
f(x) = f(f(x))
x
f
f
x
幂等操作:如果多次执行,则不会产生副作用的操作。
示例:从数据资源中检索值并打印该
值的操作 非幂等操作:如果多次执行会造成一些损害的操作。(当它们更改某些值或状态时)
示例:从银行账户提款的操作
评论
只是想抛出一个展示幂等性的真实用例。在 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');
评论
我的 5C: 在集成和网络中,幂等性非常重要。 现实生活中的几个例子: 想象一下,我们将数据传送到目标系统。由一系列消息传递的数据。 1. 如果序列在通道中混合会发生什么?(因为网络包总是:))。如果目标系统是幂等的,则结果不会有所不同。如果目标系统依赖于序列中的正确顺序,我们必须在目标站点上实现重序列器,这将恢复正确的顺序。 2. 如果消息重复会怎样?如果目标系统的通道没有及时确认,则源系统(或通道本身)通常会发送消息的另一个副本。因此,我们可以在目标系统端有重复的消息。 如果目标系统是幂等的,它会处理它,结果不会有所不同。 如果目标系统不是幂等的,我们必须在通道的目标系统端实现重复数据删除器。
评论
幂等操作是一种操作、操作或请求,可以在初始应用之后多次应用,而不会更改结果,即系统状态。
示例(WEB 应用上下文):
幂等: 发出多个相同的请求与发出单个请求具有相同的效果。电子邮件系统中的邮件被打开,并在数据库中标记为“已打开”。可以多次打开邮件,但这种重复操作只会导致该邮件处于“打开”状态。这是一个幂等操作。第一次使用与资源(系统状态)不匹配的信息对资源进行 PIT 更新时,系统状态将随着资源的更新而更改。如果一个 PIT 重复对资源进行相同的更新,则更新中的信息将在每次 PUT 时与系统中已有的信息匹配,并且不会对系统状态发生任何更改。具有相同信息的重复 PUT 是幂等的:第一个 PUT 可能会改变系统的状态,而后续 PUT 则不会。
无同位: 如果一个操作总是导致状态发生变化,比如一遍又一遍地将相同的消息 POST 给用户,导致每次都发送一条新消息并存储在数据库中,我们说该操作是非 IDEMPOTENT。
无能性: 如果一个操作没有副作用,比如纯粹在网页上显示信息而不对数据库进行任何更改(换句话说,你只是在读取数据库),我们说该操作是无效的。所有 GET 都应该是无能的。
在谈论系统状态时,我们显然忽略了希望无害且不可避免的影响,例如日志记录和诊断。
相当详细和技术性的答案。只需添加一个简单的定义。
幂等 = 可重复运行
例如,如果多次执行,则不能保证操作本身不会出错。
但是,如果有操作,则它声明可重新运行(幂等性)。Create
CreateOrUpdate
评论
简而言之,幂等操作意味着无论操作幂等操作多少次,该操作都不会产生不同的结果。
例如,根据HTTP规范的定义,是幂等操作;然而,事实并非如此。这就是为什么有时被 .GET, HEAD, PUT, and DELETE
POST and PATCH
POST
PUT
理解幂等操作的一个很好的例子可能是使用遥控钥匙锁定汽车。
log(Car.state) // unlocked
Remote.lock();
log(Car.state) // locked
Remote.lock();
Remote.lock();
Remote.lock();
log(Car.state) // locked
lock
是幂等操作。即使每次跑步时都有一些副作用,比如眨眼,但汽车仍然处于相同的锁定状态,无论你运行多少次锁定操作。lock
评论
lock()
unlock()
toggleLock()
unlocked
locked
如果多次执行操作等同于执行一次,则称其为幂等操作。
例如:将音量设置为 20。 无论电视的音量设置为 20 多少次,最终结果都是音量为 20。即使一个进程执行操作 50/100 次或更多次,在进程结束时,卷也将为 20。
反例:将音量增加 1。如果进程执行此操作 50 次,则结束卷将为初始卷 + 50,如果进程执行操作 100 次,则结束卷将为初始卷 + 100。您可以清楚地看到,最终结果会根据操作的执行次数而有所不同。因此,我们可以得出结论,此操作不是幂等的。
我用粗体突出显示了最终结果。
如果你从编程的角度来考虑,假设我有一个操作,其中一个函数作为输入,而输出设置为back。如果在进程结束时(执行此操作 50/100 次或更多次),我的变量保存操作仅执行一次时的值,则该操作是幂等的,否则不是。f
foo
f
foo
foo
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 返回输入的绝对值,则该操作是幂等的,因为无论执行多少次操作,该操作都将是 。
在这里,最终结果定义为变量的最终值。foo
abs(-2)
foo
在数学意义上,幂等性的含义略有不同:
这里的输出作为输入传递给 Again,编程并不总是如此。f(f(....f(x))) = f(x)
f(x)
f
评论
对于工作流管理器(如 Apache Airflow),如果管道中的幂等性操作失败,系统可以自动重试任务,而不会影响系统。即使日志发生了变化,这也很好,因为你可以看到事件。
在这种情况下,最重要的是您的系统可以重试失败的任务,并且不会弄乱管道(例如,每次重试都会在表中附加相同的数据)
评论
假设客户端向“IstanceA”服务发出请求,该服务处理该请求,将其传递给数据库,并在发送响应之前关闭。因为客户端没有看到它已被处理,它将重试相同的请求。负载均衡器会将请求转发到另一个服务实例“InstanceB”,该实例将对同一数据库项进行相同的更改。
我们应该使用 .当客户端向服务发送请求时,它应该有某种可以保存在数据库中的 request-id,以表明我们已经执行了请求。如果客户端重试请求,“InstanceB”将检查 requestId。由于该特定请求已执行,因此它不会对数据库项进行任何更改。这些类型的请求称为 。因此,我们会多次发送相同的请求,但不会进行任何更改idempotent tokens
idempotent requests
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
下一个:什么是尾部调用优化?
评论