什么是幂等运算?

什么是幂等运算?

答案

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

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

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

my_set.discard(x)

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

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

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

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


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

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

在 “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 节中讨论了幂等性。

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

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

例子:

  • 乘以零。无论您执行多少次,结果仍然为零。
  • 设置布尔标志。无论您执行多少次,该标志都会保持设置状态。
  • 从具有给定 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') === model('user');

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

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

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

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

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

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

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

非等幂运算:如果多次执行会导致某些危害的运算。 (当它们更改某些值或状态时)
示例:从银行帐户提取的操作

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

幂等 = 可重新运行

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

任何操作都会使第 n 个结果产生与第 1 个结果的值匹配的输出。例如,-1 的绝对值为 1。-1 的绝对值的绝对值为 1。-1 的绝对值的绝对值的绝对值为 1。依此类推。

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