ChatGPT解决这个技术问题 Extra ChatGPT

什么是幂等操作?

什么是幂等操作?


G
Greg Hewgill

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

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

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

my_set.discard(x)

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

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

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

有关详细信息,请参阅有关 idempotence 的 Wikipedia 文章。

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


示例:因为上面的答案指出 Idempotent operations are often used in the design of network protocols 这是一个相关示例 **GET 不假设更改服务器上的任何内容,因此 GET 是幂等的。在 HTTP/servlet 上下文中,这意味着可以发出两次相同的请求而不会产生负面影响。 **POST 不是幂等的。
“无状态”是“幂等”的同义词吗?
@MichaelOsofsky:不,在答案中的 Python set 示例中,set 对象显然具有状态,并且还提供了一些幂等操作,例如 discard
@MichaelOsofsky,discard 也可以通过在返回值中包含状态以无状态方式实现:discard([my_set, x]) = [my_new_set, x]。所以你可以做discard(discard([my_set, x]))。请注意,[my_new_set, x] 只是一个 参数,它的类型是 2 元组。
@Green 在阳痿的上下文中使用术语相同的效果时,它意味着结果是相同的,而不是动作。第二次调用 discard(x) 与第一次调用它的效果相同:集合将不再包含 x计算幂等性是关于系统的健壮性。由于事情可能会失败(例如网络中断),当检测到故障时,您如何恢复?最简单的恢复就是再做一次,但这只有在再做一次是幂等的情况下才有效。例如 discard(x) 是幂等的,但 pop() 不是。这都是关于错误恢复的。
J
Jim Ferrans

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

幂等性在“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 帐户信息,您可以尽可能多地 PUT 新信息,以便从 Web 服务获得确认。 PUT 一千次与 PUT 一次相同。同样,删除 REST 资源一千次与删除一次相同。因此,幂等性使得构建对通信错误具有弹性的 Web 服务变得更加容易。

进一步阅读:RESTful Web Services,Richardson 和 Ruby(幂等性在第 103-104 页讨论)和 Roy Fielding 的PhD dissertation on REST。 Fielding 是 HTTP 1.1、RFC-2616 的作者之一,它在 section 9.1.2 中讨论了幂等性。


“幂等”是一个严重超载的词,因为它听起来很夸张,并且有足够的字符来通过 sesquipedalian 检查。如果 Benjamin Peirce 选择了一个更简单的发音词,我们今天甚至不会有这个问题。
怎么理解:同样删除一个REST资源千次等于删除一次?如果该资源已被删除,您将无法再次删除该资源。
@Green,但您不是第一次删除它。您发送删除请求。重要的一点是您可以发送任意数量的请求。
@JimFerrans 我明白了。我认为可能有一些与功能相关的原因(内置于 HTTP 本身)为什么 PUT 可以毫无顾虑地重新发送而 POST 不能。现在看来,我们只需要符合 HTTP 标准,并且行为完全基于服务器的实现方式
“在算术中,给一个数加零是幂等的。”这是一个不好的例子,因为添加零不会改变任何东西。幂等意味着它(可能)改变事物,但无论是应用一次还是多次都以相同的方式。上面给出的 abs() 函数是一个更好的例子。
n
nbro

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


我听说幂等定义为以下任一或两者:1)对于给定的一组输入,它将始终返回相同的输出。 2) 不产生任何副作用。我的问题是,如果一个函数符合#1,但不符合#2,因为它会导致与计算无关的副作用(例如,将请求记录到数据存储),它仍然被认为是幂等的吗?
调用操作的结果必须包含系统的状态,所以如果操作有一些累积的副作用,它就不是幂等的;但是,如果无论调用多少次操作,副作用都会使系统处于相同状态,那么它可能是幂等的。
简短而甜蜜,我喜欢这种答案。不知道为什么我必须不断地查找这个术语,它只是不会留在我身边。
@KeithBennett,第二个定义是错误的。 “没有副作用”并不意味着幂等。幂等函数可能有副作用。例如 MySQL 的 truncatedelete
因此,如果数据库中有一个行计数器,用于检查请求输入与数据库状态的数据完整性,是否需要在幂等定义中考虑该行计数器?该行计数器将针对每个请求增加,但不会作为结果的一部分返回。
m
mikera

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

例子:

乘以零。不管你做了多少次,结果仍然是零。

设置一个布尔标志。无论你做了多少次,标志都会保持不变。

从具有给定 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) 给出 2 而 f(2) 给出 3。
@Pacerier 不,@mikera 是说纯 and 幂等意味着 f(x) = f(f(x))。但是正如@GregHewgill 提到的,为了使这个定义有意义,您必须将 x 视为一个对象,并将 f 视为改变对象状态的操作(即:f 的输出是突变 x)。
I
IVN

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

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()。在这种情况下,点击按钮不是幂等的——每次点击都会改变状态,在 unlockedlocked 之间交替。
n
nbro

即使您多次调用幂等操作,只要您传入相同的参数,它也会以相同的状态产生结果。


听起来完全不合逻辑。 stackoverflow.com/questions/1077412/…
我认为您可能会混淆幂等性和确定性。
n
nmit026

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

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

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

NON-IDEMPOTENT:如果一个操作总是导致状态的变化,比如一遍又一遍地向用户发布相同的消息,导致每次发送一条新消息并存储在数据库中,我们就说该操作是 NON-IDEMPOTENT 的。

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

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


L
Lance

只是想抛出一个演示幂等性的真实用例。在 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');

这个答案似乎不对。幂等性是关于在给定输入参数的情况下调用您希望更改某些状态的操作,如果您随后使用相同的参数再次调用该操作,则对状态没有进一步影响。但是在您的示例中,甚至在使用缓存之前,如果我们调用 model('user') 两次,这已经是幂等的,状态没有变化,只是创建一个新的不同对象并将其返回给调用者(未存储)。您正在描述一种对象标识工厂模式,该模式可确保在调用之间返回“相同”对象,这很有用但不能解释幂等性。
M
Manish Basantani

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

幂等 = 可重新运行

例如,如果执行多次,则 Create 操作本身不能保证无错误地运行。但是如果有一个操作 CreateOrUpdate 那么它说明了可重运行性(幂等性)。


这是一个欺骗性的定义。可重运行性并不能保证是幂等的。一个操作可以重新运行,并且在每次运行中它可以为结果添加额外的效果,因此它不是幂等的。
M
Mahmoud Abou-Eita

幂等操作:多次执行没有副作用的操作。示例:从数据资源中检索值并打印出来的操作 非幂等操作:如果多次执行会造成一定危害的操作。 (因为它们改变了一些值或状态) 示例:从银行账户取款的操作


其实是一个错误的答案!对于幂等操作说“没有副作用”是不对的。对于非幂等操作说“造成一些伤害”是一个令人困惑的答案。
O
Oorang

这是任何操作,每第 n 个结果将导致输出与第一个结果的值匹配。比如-1的绝对值是1。-1的绝对值的绝对值是1。-1的绝对值的绝对值的绝对值是1。以此类推。

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


即使在 10 年后,这也是一个精辟的答案。 +1
A
Arnkrishn

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

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

它可以是二元运算,例如集合与自身的联合总是返回相同的集合。

干杯


幂等运算是 f(f(x)) = f(x) 的运算。 “保持其成员不变”不是正确答案。
C
Community

简而言之,幂等操作是指无论你对幂等操作操作多少次,操作都不会导致不同的结果。

例如,根据HTTP规范的定义,GET, HEAD, PUT, and DELETE是幂等操作;但是 POST and PATCH 不是。这就是为什么有时 POST 会被 PUT 代替。


A
Aman Godara

如果多次执行一个操作相当于执行一次,则称该操作是幂等的。

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

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

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

如果您从编程的角度考虑,假设我有一个操作,其中函数 ffoo 作为输入,并将 f 的输出设置为 foo。如果在进程结束时(执行此操作 50/100 次或更多),我的 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 的最终值。

在数学意义上,幂等性的含义略有不同:
f(f(....f(x))) = f(x)
这里 f(x) 的输出再次作为输入传递给 f,而编程并不总是如此。


L
Leonid Ganeline

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


与任何其他请求(或任何其他改变系统状态的事件)隔离发送的单个请求的幂等性与重新排序请求不同。 HTTP PUT 请求和 HTTP DELETE 请求都应该是单独的幂等的——但这并不意味着在同一个 URL 上调用 PUT 和 DELETE 的顺序无关紧要,因为 PUT 请求可能有副作用!
A
Abimael Domínguez

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

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


但在上面之前先简单解释一下“幂等性操作”。