Câu trả lời:
Trong điện toán, một hoạt động bình thường là một hoạt động không có tác dụng bổ sung nếu nó được gọi nhiều lần với cùng một tham số đầu vào. Ví dụ: xóa một mục khỏi một tập hợp có thể được coi là một hoạt động bình thường trên tập hợp.
Trong toán học, một phép toán idempotent là một phép toán trong đó f (f (x)) = f (x) . Ví dụ, abs()
hàm là idempotent vì abs(abs(x)) = abs(x)
cho tất cả x
.
Các định nghĩa hơi khác nhau này có thể được đối chiếu bằng cách xem xét x trong định nghĩa toán học đại diện cho trạng thái của một đối tượng và f là một hoạt động có thể làm thay đổi đối tượng đó. Ví dụ, hãy xem xét Pythonset
và discard
phương thức của nó . Các discard
phương pháp loại bỏ một phần tử từ một tập, và không có gì nếu nguyên tố này không tồn tại. Vì thế:
my_set.discard(x)
có tác dụng chính xác giống như thực hiện hai thao tác hai lần:
my_set.discard(x)
my_set.discard(x)
Các hoạt động tạm thời thường được sử dụng trong thiết kế các giao thức mạng, trong đó yêu cầu thực hiện thao tác được đảm bảo xảy ra ít nhất một lần, nhưng cũng có thể xảy ra nhiều lần. Nếu hoạt động là idempotent, thì không có hại trong việc thực hiện hoạt động hai lần trở lên.
Xem bài viết Wikipedia về idempotence để biết thêm thông tin.
Câu trả lời trên trước đây có một số ví dụ không chính xác và sai lệch. Bình luận dưới đây được viết trước tháng 4 năm 2014 đề cập đến một phiên bản cũ hơn.
set
ví dụ Python trong câu trả lời, đối tượng tập hợp rõ ràng có trạng thái và cũng cung cấp một số hoạt động tạm thời như discard
.
discard
cũng có thể được thực hiện theo cách không trạng thái bằng cách bao gồm trạng thái trong giá trị trả về : discard([my_set, x]) = [my_new_set, x]
. Vì vậy, bạn có thể làm discard(discard([my_set, x]))
. Lưu ý rằng [my_new_set, x]
là chỉ là một đối số và kiểu của nó là 2-tuple.
discard(x)
lần thứ hai sẽ có tác dụng tương tự như gọi lần thứ nhất: Tập hợp sẽ không còn chứa x
. Tính toán idempotence là về sự mạnh mẽ của một hệ thống. Vì mọi thứ có thể thất bại (ví dụ như mất mạng), khi phát hiện lỗi, bạn sẽ phục hồi như thế nào? Phục hồi đơn giản nhất là chỉ cần làm lại, nhưng điều đó chỉ hoạt động nếu thực hiện lại là không cần thiết. Ví dụ discard(x)
là idempotent, nhưng pop()
không. Đó là tất cả về phục hồi lỗi.
Một hoạt động bình thường có thể được lặp đi lặp lại một số lần tùy ý và kết quả sẽ giống như khi nó được thực hiện chỉ một lần. Trong số học, việc thêm số 0 vào một số là không có giá trị.
Idempotence được nói đến rất nhiều trong bối cảnh dịch vụ web "RESTful". REST tìm cách tận dụng tối đa HTTP để cung cấp cho các chương trình quyền truy cập vào nội dung web và thường được đặt trái ngược với các dịch vụ web dựa trên SOAP, chỉ cung cấp các dịch vụ kiểu gọi thủ tục từ xa trong các yêu cầu và phản hồi HTTP.
REST tổ chức một ứng dụng web thành "tài nguyên" (như người dùng Twitter hoặc hình ảnh Flickr) và sau đó sử dụng các động từ HTTP của POST, PUT, GET và DELETE để tạo, cập nhật, đọc và xóa các tài nguyên đó.
Idempotence đóng một vai trò quan trọng trong REST. Nếu bạn NHẬN đại diện cho tài nguyên REST (ví dụ: NHẬN hình ảnh jpeg từ Flickr) và thao tác không thành công, bạn có thể lặp lại GET một lần nữa cho đến khi thao tác thành công. Đối với dịch vụ web, không có vấn đề bao nhiêu lần hình ảnh được nhận. Tương tự, nếu bạn sử dụng dịch vụ web RESTful để cập nhật thông tin tài khoản Twitter của mình, bạn có thể PUT thông tin mới nhiều lần để nhận được xác nhận từ dịch vụ web. PUT-ing nó một ngàn lần cũng giống như PUT-ing nó một lần. Tương tự XÓA-ing một tài nguyên REST một nghìn lần cũng giống như xóa nó một lần. Do đó, idempotence giúp xây dựng một dịch vụ web dễ dàng hơn với các lỗi giao tiếp.
Đọc thêm: Dịch vụ web RESTful , của Richardson và Ruby (tính không thay đổi được thảo luận ở trang 103-104) và luận án tiến sĩ của Roy Fielding về REST . Fielding là một trong những tác giả của HTTP 1.1, RFC-2616, nói về sự không ổn định trong phần 9.1.2 .
Cho dù bạn gọi thao tác bao nhiêu lần, kết quả sẽ giống nhau.
truncate
và delete
.
Idempotence có nghĩa là áp dụng một hoạt động một lần hoặc áp dụng nó nhiều lần có hiệu quả tương tự.
Ví dụ:
Đối với các hàm thuần túy (các hàm không có tác dụng phụ) thì idempotency ngụ ý rằng f (x) = f (f (x)) = f (f (f (x))) = f (f (f (f (x))) ) = ...... cho tất cả các giá trị của x
Đối với các chức năng có tác dụng phụ , tính không ổn định hơn nữa ngụ ý rằng không có tác dụng phụ bổ sung nào sẽ được gây ra sau ứng dụng đầu tiên. Bạn có thể coi trạng thái của thế giới là một tham số "ẩn" bổ sung cho hàm nếu bạn muốn.
Lưu ý rằng trong một thế giới nơi bạn có các hành động xảy ra đồng thời, bạn có thể thấy rằng các hoạt động mà bạn nghĩ là không còn tồn tại nữa (ví dụ, một luồng khác có thể bỏ đặt giá trị của cờ boolean trong ví dụ trên). Về cơ bản bất cứ khi nào bạn có trạng thái đồng thời và có thể thay đổi, bạn cần suy nghĩ kỹ hơn về tính không ổn định.
Idempotency thường là một tài sản hữu ích trong việc xây dựng các hệ thống mạnh mẽ. Ví dụ: nếu có rủi ro bạn có thể nhận được một tin nhắn trùng lặp từ bên thứ ba, thì việc xử lý tin nhắn hoạt động như một hoạt động bình thường là rất hữu ích để hiệu ứng tin nhắn chỉ xảy ra một lần.
f(x) = f(f(x))
, bạn có nghĩa đó f(x){return x+1;}
không phải là một hàm thuần túy? bởi vì f(x) != f(f(x))
: f(1)
cho 2 trong khi f(2)
cho 3.
f(x) = f(f(x))
. Nhưng như @GregHewgill đã đề cập, để định nghĩa này có ý nghĩa, bạn phải xem xét x
như một đối tượng và f
như một hoạt động làm thay đổi trạng thái của đối tượng (nghĩa là: đầu ra của f
là một đột biến x
).
Một hoạt động bình thường tạo ra kết quả trong cùng một trạng thái ngay cả khi bạn gọi nó nhiều lần, miễn là bạn vượt qua trong cùng một tham số.
Chỉ muốn ném ra một trường hợp sử dụng thực sự thể hiện sự bình tĩnh. Trong JavaScript, giả sử bạn đang định nghĩa một loạt các lớp mô hình (như trong mô hình MVC). Cách thức này thường được thực hiện tương đương về mặt chức năng với một cái gì đó như thế này (ví dụ cơ bản):
function model(name) {
function Model() {
this.name = name;
}
return Model;
}
Sau đó, bạn có thể định nghĩa các lớp mới như thế này:
var User = model('user');
var Article = model('article');
Nhưng nếu bạn cố gắng đưa User
lớp qua model('user')
, từ một nơi khác trong mã, nó sẽ thất bại:
var User = model('user');
// ... then somewhere else in the code (in a different scope)
var User = model('user');
Hai nhà User
xây dựng sẽ khác nhau. Đó là,
model('user') !== model('user');
Để làm cho nó không hoạt động , bạn chỉ cần thêm một số loại cơ chế bộ đệm, như thế này:
var collection = {};
function model(name) {
if (collection[name])
return collection[name];
function Model() {
this.name = name;
}
collection[name] = Model;
return Model;
}
Bằng cách thêm bộ nhớ đệm, mỗi lần bạn thực hiện model('user')
nó sẽ là cùng một đối tượng và do đó, nó là idempotent. Vì thế:
model('user') === model('user');
Một hoạt động bình thường là một hoạt động, hành động hoặc yêu cầu có thể được áp dụng nhiều lần mà không thay đổi kết quả, tức là trạng thái của hệ thống, ngoài ứng dụng ban đầu.
VÍ DỤ (TIẾP THEO WEB):
IDEMPOTENT: Thực hiện nhiều yêu cầu giống hệt nhau có tác dụng tương tự như thực hiện một yêu cầu. Một tin nhắn trong một hệ thống nhắn tin email được mở và được đánh dấu là "đã mở" trong cơ sở dữ liệu. Người ta có thể mở tin nhắn nhiều lần nhưng hành động lặp đi lặp lại này sẽ chỉ dẫn đến việc tin nhắn đó ở trạng thái "mở". Đây là một hoạt động bình thường. Lần đầu tiên PUT cập nhật tài nguyên bằng thông tin không khớp với tài nguyên (trạng thái của hệ thống), trạng thái của hệ thống sẽ thay đổi khi tài nguyên được cập nhật. Nếu một PUT liên tục cập nhật cùng một tài nguyên thì thông tin trong bản cập nhật sẽ khớp với thông tin đã có trong hệ thống trên mỗi PUT và sẽ không có thay đổi nào về trạng thái của hệ thống. PUT lặp đi lặp lại với cùng thông tin là idempotent:
NON-IDEMPOTENT: Nếu một thao tác luôn gây ra thay đổi trạng thái, như gửi tin nhắn giống nhau cho người dùng nhiều lần, dẫn đến một tin nhắn mới được gửi và lưu trữ trong cơ sở dữ liệu mỗi lần, chúng tôi nói rằng hoạt động đó là KHÔNG TỪNG IDEMPOTENT.
NULLIPOTENT: Nếu một thao tác không có tác dụng phụ, như hoàn toàn hiển thị thông tin trên trang web mà không có bất kỳ thay đổi nào trong cơ sở dữ liệu (nói cách khác bạn chỉ đọc cơ sở dữ liệu), chúng tôi nói rằng hoạt động đó là NULLIPOTENT. Tất cả các GET phải là nullipotent.
Khi nói về trạng thái của hệ thống, rõ ràng chúng ta đang bỏ qua những tác động hy vọng vô hại và không thể tránh khỏi như đăng nhập và chẩn đoán.
Hoạt động tạm thời: Các hoạt động không có tác dụng phụ nếu được thực hiện nhiều lần.
Ví dụ : Một hoạt động truy xuất các giá trị từ tài nguyên dữ liệu và nói rằng, in nó
Hoạt động không phải là Idempotent: Các hoạt động sẽ gây ra một số tác hại nếu được thực hiện nhiều lần. (Khi họ thay đổi một số giá trị hoặc trạng thái)
Ví dụ: Một hoạt động rút tiền từ tài khoản ngân hàng
Khá là một câu trả lời chi tiết và kỹ thuật. Chỉ cần thêm một định nghĩa đơn giản.
Idempotent = Chạy lại
Ví dụ,
Create
hoạt động tự nó không được đảm bảo để chạy mà không có lỗi nếu được thực hiện nhiều lần. Nhưng nếu có một hoạt động CreateOrUpdate
thì nó nêu khả năng chạy lại (Idempotency).
Một hoạt động tạm thời trên một tập hợp làm cho các thành viên của nó không thay đổi khi được áp dụng một hoặc nhiều lần.
Nó có thể là một phép toán đơn nguyên như tuyệt đối (x) trong đó x thuộc về một tập hợp các số nguyên dương. Ở đây tuyệt đối (tuyệt đối (x)) = x.
Nó có thể là một hoạt động nhị phân như liên kết của một tập hợp với chính nó sẽ luôn trả về cùng một tập hợp.
chúc mừng
Đó là bất kỳ hoạt động nào mà mọi kết quả thứ n sẽ dẫn đến kết quả đầu ra khớp với giá trị của kết quả thứ 1. Chẳng hạn, giá trị tuyệt đối của -1 là 1. Giá trị tuyệt đối của giá trị tuyệt đối của -1 là 1. Giá trị tuyệt đối của giá trị tuyệt đối của giá trị tuyệt đối của -1 là 1. Và cứ thế.
Xem thêm: Khi nào sẽ là một thời gian thực sự ngớ ngẩn để sử dụng đệ quy?
Một ví dụ điển hình về việc hiểu một hoạt động bình thường có thể là khóa xe bằng chìa khóa từ xa.
log(Car.state) // unlocked
Remote.lock();
log(Car.state) // locked
Remote.lock();
Remote.lock();
Remote.lock();
log(Car.state) // locked
lock
là một hoạt động bình thường. Ngay cả khi có một số tác dụng phụ mỗi khi bạn chạy lock
, như chớp mắt, chiếc xe vẫn trong tình trạng bị khóa, bất kể bạn chạy bao nhiêu lần hoạt động khóa.
my 5c: Trong tích hợp và kết nối mạng, tính không thay đổi là rất quan trọng. Một số ví dụ từ đời thực: Hãy tưởng tượng, chúng tôi cung cấp dữ liệu cho hệ thống đích. Dữ liệu được phân phối bởi một chuỗi các tin nhắn. 1. Điều gì sẽ xảy ra nếu chuỗi được trộn trong kênh? (Như các gói mạng luôn làm :)). Nếu hệ thống đích là idempotent, kết quả sẽ không khác. Nếu hệ thống đích phụ thuộc vào thứ tự đúng trong chuỗi, chúng ta phải triển khai resequencer trên trang đích, sẽ khôi phục đúng thứ tự. 2. Điều gì sẽ xảy ra nếu có các thông điệp trùng lặp? Nếu kênh của hệ thống đích không xác nhận kịp thời, hệ thống nguồn (hoặc chính kênh) thường gửi một bản sao khác của tin nhắn. Kết quả là chúng ta có thể có thông điệp trùng lặp ở phía hệ thống đích. Nếu hệ thống đích là idempotent, nó chăm sóc nó và kết quả sẽ không khác nhau. Nếu hệ thống đích không phải là idempotent, chúng ta phải triển khai bộ sao chép ở phía hệ thống đích của kênh.
Nói ngắn gọn , hoạt động Idempotent có nghĩa là hoạt động sẽ không dẫn đến kết quả khác nhau cho dù bạn có vận hành các hoạt động tạm thời bao nhiêu lần.
Ví dụ, theo định nghĩa về thông số kỹ thuật của HTTP, GET, HEAD, PUT, and DELETE
là các hoạt động tạm thời; tuy nhiên POST and PATCH
thì không. Đó là lý do tại sao đôi khi POST
được thay thế bởi PUT
.
thử lại an toàn.
Thường là cách dễ nhất để hiểu ý nghĩa của nó trong khoa học máy tính.
Idempotent operations are often used in the design of network protocols
đây là một ví dụ có liên quan ** GET không giả sử thay đổi bất cứ điều gì trên máy chủ, vì vậy GET là, idempotent. Trong bối cảnh HTTP / servlet, điều đó có nghĩa là cùng một yêu cầu có thể được thực hiện hai lần mà không có hậu quả tiêu cực. ** POST không phải là idempotent.