Sự khác biệt giữa các kiến ​​trúc: Không đồng bộ, Không chặn, Cơ sở sự kiện là gì?


84
  1. Sự khác biệt giữa:

    • Không đồng bộ ,
    • Không chặn
    • Kiến trúc cơ sở sự kiện ?
  2. Một cái gì đó có thể là cả không đồng bộkhông chặn (và dựa trên sự kiện )?

  3. Điều gì quan trọng nhất trong lập trình, để có một cái gì đó: không đồng bộ, không chặn và / hoặc cơ sở sự kiện (hoặc cả 3)?

Nếu bạn có thể cung cấp các ví dụ, điều đó sẽ rất tuyệt.

Câu hỏi này đang được đặt ra vì tôi đang đọc bài viết tuyệt vời này của StackOverflow về một chủ đề tương tự nhưng nó không trả lời các câu hỏi của tôi ở trên.

Câu trả lời:


91

Asynchronous Asynchronous theo nghĩa đen có nghĩa là không đồng bộ. Email không đồng bộ. Bạn gửi thư, bạn không mong đợi nhận được phản hồi NGAY BÂY GIỜ. Nhưng nó không phải là không chặn. Về cơ bản, ý nghĩa của nó là một kiến ​​trúc nơi các "thành phần" gửi thông điệp cho nhau mà không mong đợi phản hồi ngay lập tức. Các yêu cầu HTTP là đồng bộ. Gửi yêu cầu và nhận phản hồi.

Không chặn Thuật ngữ này chủ yếu được sử dụng với IO. Điều này có nghĩa là khi bạn thực hiện một cuộc gọi hệ thống, nó sẽ trả về ngay lập tức với bất kỳ kết quả nào mà nó có mà không đặt luồng của bạn vào trạng thái ngủ (với xác suất cao). Ví dụ, các cuộc gọi đọc / ghi không chặn sẽ trả về bất cứ điều gì họ có thể làm và mong đợi người gọi thực hiện lại cuộc gọi. try_lock chẳng hạn là cuộc gọi không chặn. Nó sẽ chỉ khóa nếu có thể có được khóa. Ngữ nghĩa thông thường cho các cuộc gọi hệ thống đang bị chặn. read sẽ đợi cho đến khi nó có một số dữ liệu và đặt chuỗi gọi vào chế độ ngủ.

Cơ sở sự kiện Thuật ngữ này xuất phát từ sự tự do. Bản thân các cuộc gọi đọc / ghi không chặn là vô ích vì chúng không cho bạn biết "khi nào" bạn nên gọi lại (thử lại). select / epoll / IOCompletionPort, v.v. là các cơ chế khác nhau để tìm ra từ OS "khi nào" các cuộc gọi này được mong đợi trả về dữ liệu "thú vị". libevent và các thư viện khác như vậy cung cấp các trình bao bọc trên các phương tiện giám sát sự kiện này được cung cấp bởi các hệ điều hành khác nhau và cung cấp một API nhất quán để hoạt động trên các hệ điều hành. IO không chặn đi đôi với Event-base.

Tôi nghĩ rằng những điều khoản này trùng lặp. Ví dụ: giao thức HTTP là đồng bộ nhưng việc triển khai HTTP sử dụng IO không chặn có thể không đồng bộ. Một lần nữa, một lệnh gọi API không chặn như read / write / try_lock là đồng bộ (nó ngay lập tức đưa ra phản hồi) nhưng "xử lý dữ liệu" là không đồng bộ.


2
Điểm tốt về tính năng không chặn yêu cầu thăm dò liên tục, trong khi không đồng bộ có thể dựa trên đẩy.
Alexander Torstling

Bạn đã định nghĩa đồng bộ là nhận được phản hồi ngay lập tức, nhưng khi tôi google đồng bộ tất cả các từ điển định nghĩa nó là 'xảy ra cùng một lúc', không phải 'phản hồi ngay lập tức'.
IntelliData

4
Làm thế nào để tôi bị chặn khi tôi gửi email nhưng không mong đợi câu trả lời? Tôi có thể bận tâm việc riêng của mình trong khi chờ phản hồi.
Koray Tugay

20

Trong phần cứng không đồng bộ, mã yêu cầu một số thực thể làm điều gì đó và được tự do làm những việc khác trong khi hành động được thực hiện; khi hành động hoàn tất, thực thể thường sẽ báo hiệu mã theo một số cách. Một kiến ​​trúc không chặn sẽ ghi chú các hành động xảy ra tự nhiên mà mã có thể quan tâm và cho phép mã hỏi những hành động như vậy đã xảy ra, nhưng mã sẽ chỉ nhận biết được các hành động đó khi nó hỏi rõ ràng về chúng. Một kiến ​​trúc dựa trên sự kiện sẽ thông báo một cách chắc chắn mã khi các sự kiện xảy ra một cách tự nhiên.

Hãy xem xét một cổng nối tiếp, từ đó mã sẽ muốn nhận 1.000 byte.

Trong kiến ​​trúc chặn-đọc, mã sẽ đợi cho đến khi 1.000 byte đến hoặc nó quyết định từ bỏ.

Trong kiến ​​trúc đọc không đồng bộ, mã sẽ cho trình điều khiển biết nó muốn 1.000 byte và sẽ được thông báo khi 1.000 byte đến.

Trong kiến ​​trúc không chặn, mã có thể hỏi bất kỳ lúc nào có bao nhiêu byte đến và có thể đọc bất kỳ hoặc tất cả dữ liệu đó khi nó thấy phù hợp, nhưng cách duy nhất nó có thể biết khi nào tất cả dữ liệu đã đến là hỏi; nếu mã muốn tìm ra trong vòng một phần tư giây khi byte thứ 1000 đến, nó phải kiểm tra mỗi phần tư giây hoặc lâu hơn.

Trong kiến ​​trúc dựa trên sự kiện, trình điều khiển cổng nối tiếp sẽ thông báo cho ứng dụng bất kỳ khi nào có dữ liệu đến. Trình điều khiển sẽ không biết ứng dụng muốn có bao nhiêu byte, vì vậy ứng dụng phải có khả năng xử lý các thông báo cho số lượng nhỏ hơn hoặc lớn hơn những gì ứng dụng muốn.


5

Vì vậy, để trả lời câu hỏi đầu tiên và thứ hai của bạn:

Tính năng không chặn cũng giống như không đồng bộ - bạn thực hiện cuộc gọi và bạn sẽ nhận được kết quả sau đó, nhưng trong khi điều đó xảy ra, bạn có thể làm điều gì đó khác. Chặn thì ngược lại. Bạn chờ cuộc gọi quay lại trước khi tiếp tục hành trình.

Giờ đây, mã Async / Non-block nghe có vẻ tuyệt vời và đúng như vậy. Nhưng tôi có lời cảnh báo. Không chặn / Không chặn rất tuyệt vời khi làm việc trong môi trường hạn chế, chẳng hạn như trong điện thoại di động ... hãy xem xét CPU / bộ nhớ hạn chế. Nó cũng tốt cho phát triển front-end, nơi mã của bạn cần phản ứng với tiện ích giao diện người dùng theo một cách nào đó.

Không đồng bộ là cơ bản đối với cách tất cả các hệ điều hành cần hoạt động - chúng sẽ giúp bạn hoàn thành công việc ở chế độ nền và đánh thức mã của bạn khi chúng đã thực hiện những gì bạn yêu cầu và khi cuộc gọi đó không thành công, bạn đã nói là không. hoạt động bởi một ngoại lệ hoặc một số loại mã trả lại / đối tượng lỗi.

Tại thời điểm khi mã của bạn yêu cầu điều gì đó sẽ mất một lúc để trả lời, hệ điều hành của bạn biết rằng nó có thể bận rộn với việc làm những thứ khác. Mã của bạn - một quy trình, chuỗi hoặc tương đương, các khối. Mã của bạn hoàn toàn không biết về những gì khác đang diễn ra trong Hệ điều hành trong khi chờ kết nối mạng đó được thực hiện hoặc trong khi chờ phản hồi đó từ một yêu cầu HTTP hoặc trong khi chờ đọc / ghi tệp đó, và Sớm. Mã của bạn có thể "đơn giản là" đang chờ một cú nhấp chuột. Điều thực sự đang diễn ra trong thời gian đó là hệ điều hành của bạn đang quản lý, lập lịch và phản ứng liên tục với các "sự kiện" - những thứ mà hệ điều hành đang tìm kiếm, chẳng hạn như quản lý bộ nhớ, I / O (bàn phím, chuột đĩa, internet), các tác vụ khác, khôi phục lỗi, v.v.

Hệ điều hành là lõi cứng. Họ thực sự giỏi trong việc ẩn tất cả những thứ phức tạp về không đồng bộ / không chặn khỏi bạn lập trình viên. Và đó là cách hầu hết các lập trình viên đạt được vị trí của chúng ta ngày nay với phần mềm. Bây giờ chúng ta đang đạt đến giới hạn CPU, mọi người đang nói rằng mọi thứ có thể được thực hiện song song để cải thiện hiệu suất. Điều này có nghĩa là Async / non-block dường như là một điều rất thuận lợi để làm và vâng, nếu phần mềm của bạn yêu cầu, tôi có thể đồng ý.

Nếu bạn đang viết một máy chủ web back-end thì hãy tiến hành một cách thận trọng. Hãy nhớ rằng bạn có thể mở rộng theo chiều ngang với giá rẻ hơn nhiều. Netflix / Amazon / Google / Facebook là những trường hợp ngoại lệ rõ ràng đối với quy tắc này, hoàn toàn là vì nó rẻ hơn khi họ sử dụng ít phần cứng hơn.

Tôi sẽ cho bạn biết tại sao mã không đồng bộ / không chặn lại là cơn ác mộng với các hệ thống back-end ....

1) Nó trở thành một sự từ chối dịch vụ về năng suất ... bạn phải suy nghĩ RẤT NHIỀU hơn, và bạn mắc rất nhiều sai lầm trong quá trình làm việc.

2) Dấu vết ngăn xếp trong mã phản ứng trở nên không thể giải mã - thật khó để biết cái gì được gọi là gì, khi nào, tại sao và như thế nào. Chúc may mắn với việc gỡ lỗi.

3) Bạn phải suy nghĩ nhiều hơn về việc mọi thứ thất bại như thế nào, đặc biệt là khi nhiều thứ trở lại không đúng như cách bạn đã gửi chúng. Trong thế giới cũ, bạn đã làm từng việc một.

4) Khó hơn để kiểm tra.

5) Khó duy trì hơn.

6) Thật đau đớn. Lập trình phải là một niềm vui và niềm vui. Chỉ những kẻ tự bạo mới thích sự đau đớn. Những người viết các khuôn khổ đồng thời / phản ứng là những kẻ tàn bạo.

Và có, tôi đã viết cả đồng bộ và không đồng bộ. Tôi thích đồng bộ hơn vì 99,99 ứng dụng back-end có thể sử dụng với mô hình này. Các ứng dụng front-end cần mã phản ứng, không cần câu hỏi và đó luôn là cách.

  1. Có, mã có thể không đồng bộ, không chặn VÀ dựa trên sự kiện.

  2. Điều quan trọng nhất trong lập trình là đảm bảo mã của bạn hoạt động và phản hồi trong một khoảng thời gian có thể chấp nhận được. Hãy tuân thủ nguyên tắc quan trọng đó và bạn không thể sai lầm.


** CẬP NHẬT ** Sau khi chơi với cờ vây, và xem xét các kênh và thói quen đi lại, tôi phải nói rằng tôi thực sự thích làm cho mã của mình đồng thời hơn, bởi vì các cấu trúc của ngôn ngữ này lấy đi mọi thứ khó khăn từ những người viết khung Sadist. Chúng tôi có một "từ an toàn" trong thế giới xử lý không đồng bộ - và đó là "Go!"
user924272

4

Đối với tôi, không chặn có nghĩa là việc thực hiện một hành động trong một luồng không phụ thuộc vào việc thực thi các luồng khác, nó đặc biệt không yêu cầu phần phê bình.

Không đồng bộ có nghĩa là tác động xảy ra bên ngoài luồng của người gọi và có khả năng bị ảnh hưởng. Việc thực thi thường xảy ra trong một luồng khác.

Đọc dữ liệu đồng thời là không chặn (không cần khóa), nhưng đồng bộ. Ngược lại, việc ghi dữ liệu đồng thời theo cách đồng bộ đang bị chặn (yêu cầu một khóa riêng). Một cách để làm cho nó không bị chặn theo quan điểm của luồng chính là làm cho việc ghi không đồng bộ và trì hoãn việc thực thi của chúng.

Khái niệm sự kiện là một cái gì đó khác, nói một cách đại khái có nghĩa là bạn được thông báo khi có điều gì đó xảy ra. Nếu quá trình ghi được thực hiện không đồng bộ, một sự kiện có thể được đưa ra để thông báo cho các phần khác của hệ thống khi quá trình ghi đã được thực hiện. Các bộ phận khác sẽ trả lời sự kiện. Hệ thống có thể được xây dựng chỉ dựa trên các sự kiện như là cách duy nhất để giao tiếp giữa các thành phần (hãy nghĩ đến mô hình tác nhân), nhưng nó không nhất thiết phải như vậy.

Ba thuật ngữ có liên quan với nhau, nhưng là những khái niệm khác nhau đối với tôi. Tuy nhiên, có thể mọi người sử dụng chúng theo cách có thể hoán đổi cho nhau.


2

Nói chung, một kiến ​​trúc không chặn dựa trên các cuộc gọi phương thức, mặc dù chúng có thể thực thi trong một thời gian dài trên luồng công nhân , nhưng không chặn luồng gọi . Nếu luồng gọi cần lấy thông tin về hoặc từ tác vụ mà luồng công nhân đang thực hiện, thì luồng gọi thực hiện điều đó là tùy thuộc vào.

Kiến trúc dựa trên sự kiện dựa trên khái niệm mã được thực thi để đáp ứng với các sự kiện được kích hoạt. Thời gian thực thi mã thường không xác định, nhưng các sự kiện có thể gọi ra các phương thức chặn; chỉ vì hệ thống dựa trên sự kiện không có nghĩa là mọi thứ nó làm đều không bị chặn.

Nói chung, kiến ​​trúc không đồng bộ là kiến ​​trúc dựa trên sự kiện, không chặn.

Khi một cuộc gọi không đồng bộ được thực hiện, trình xử lý sự kiện được đăng ký với API cung cấp dịch vụ đồng bộ hóa, để thông báo cho người gọi rằng điều mà người gọi quan tâm đã xảy ra. Sau đó, cuộc gọi ngay lập tức trở lại (hành vi không chặn) và người gọi có thể tự do tiếp tục thực hiện. Khi các sự kiện được kích hoạt trở lại quy trình gọi, chúng sẽ được xử lý trên một số luồng trong quy trình đó.

Điều quan trọng là phải hiểu liệu các sự kiện có được xử lý trên cùng một luồng hay không, vì điều này sẽ ảnh hưởng đến tính chất không chặn của việc thực thi, nhưng cá nhân tôi không biết về bất kỳ thư viện nào thực hiện quản lý thực thi không đồng bộ trên một luồng duy nhất.

Tôi đã xóa đoạn trên vì nó không đúng như đã nêu. Ý định của tôi là nói rằng mặc dù các hoạt động trong hệ thống là không chặn, chẳng hạn như thực hiện các lệnh gọi tới một cơ sở hệ điều hành và tiếp tục thực thi, bản chất của thực thi đơn luồng có nghĩa là khi các sự kiện được kích hoạt, chúng sẽ cạnh tranh với các tác vụ xử lý khác cho thời gian tính toán trên luồng.


Không phải đoạn cuối cùng của bạn mâu thuẫn với tuyên bố của bạn rằng "kiến trúc không đồng bộ là ... không chặn"
nickb

Tôi đoán tôi đã không làm rất tốt việc giải quyết phần "định nghĩa" trong câu hỏi của bạn; Tôi sẽ đăng một bản cập nhật. Nhưng không, bản chất của thực thi đơn luồng là mọi hoạt động vốn đã bị chặn trong khi nó đang chạy , điều này làm cho tính không đồng bộ thậm chí còn hữu ích hơn.
arootbeer 28/10/11
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.