Có phải các sự kiện chỉ được sử dụng cho lập trình GUI?


57

Có phải các sự kiện chỉ được sử dụng cho lập trình GUI?

Làm thế nào để bạn xử lý trong lập trình phụ trợ bình thường khi một cái gì đó xảy ra với điều này khác?


6
Nhân tiện, Nguồn sự kiện là một khái niệm hoàn toàn trực giao với Lập trình sự kiện. Khái niệm cơ bản của Tìm nguồn sự kiện là bạn lưu trữ "sự kiện" hoặc "thay đổi" vào hệ thống của mình, thay vì lưu trữ "trạng thái" của hệ thống. Ví dụ: bạn có thể mô hình hóa tài khoản ngân hàng của mình dưới dạng a) Số dư của bạn (NHÀ NƯỚC) hoặc b) Một loạt các Giao dịch (SỰ KIỆN).
ArTs

4
Tùy thuộc vào cách sử dụng, một "sự kiện" thường chỉ là một số hình thức gọi lại được bọc bằng đường. Các cuộc gọi lại được sử dụng ở mọi nơi - nếu bạn quan tâm, đó có lẽ là một từ khóa tốt để bắt đầu tìm kiếm.
J ...

10
Tôi cũng sẽ chỉ ra rằng ngay cả khi bạn đi ở mức độ thấp như một vi điều khiển, bạn sẽ thấy phần cứng làm gián đoạn một tính năng hữu ích và có thể gây tranh cãi. Tuyệt vời cho các hệ thống điều khiển, hoặc IO cơ bản như máy pha cà phê. Những gián đoạn phần cứng này thực sự không khác biệt với các sự kiện.
Dan

Không! Ví dụ thực tế: Sự kiện
Nodejs

2
Bạn có trên Windows không? Kiểm tra Trình xem sự kiện. Chúc vui vẻ.
Marc.2377

Câu trả lời:


106

Không. Chúng thực sự tiện dụng để triển khai Trình quan sát và đảm bảo rằng các lớp được đóng để sửa đổi.

Giả sử chúng ta có một phương thức đăng ký người dùng mới.

public void Register(user) {
    db.Save(user);
}

Sau đó, một người nào đó quyết định rằng một email nên được gửi. Chúng ta có thể làm điều này:

public void Register(user) {
    db.Save(user);
    emailClient.Send(new RegistrationEmail(user));
}

Nhưng chúng tôi vừa sửa đổi một lớp được cho là đã đóng để sửa đổi. Có lẽ tốt cho mã giả đơn giản này, nhưng có thể là cách để điên rồ trong mã sản xuất. Mất bao lâu cho đến khi phương thức này là 30 dòng mã mà hầu như không liên quan đến mục đích ban đầu là tạo người dùng mới ??

Sẽ tốt hơn nhiều khi để lớp thực hiện chức năng cốt lõi của nó và đưa ra một sự kiện cho biết bất cứ ai đang nghe rằng người dùng đã đăng ký và họ có thể thực hiện bất kỳ hành động nào họ cần thực hiện (chẳng hạn như gửi email).

public void Register(user) {
    db.Save(user);

    RaiseUserRegisteredEvent(user);
}

Điều này giữ cho mã của chúng tôi sạch sẽ và linh hoạt. Một trong những phần thường bị bỏ qua của OOP là các lớp gửi tin nhắn cho nhau. Sự kiện là những tin nhắn.


37
Tôi đọc nó và nghĩ về mã "tạo đặt chỗ" của chúng tôi và tôi khóc một lúc và mong muốn một nơi tốt hơn: '(
sara

1
+1, câu trả lời tuyệt vời. Chỉ là một câu hỏi tiếp tuyến (điều này làm phiền tôi một chút): có lý do đặc biệt nào để bạn bắt đầu tên phương thức của mình (Đăng ký, Lưu và Gửi) bằng chữ in hoa không? Tất nhiên, điều này không ảnh hưởng đến tính hữu ích của câu trả lời này.
Pedro A

14
@Rouletteiffic Tôi chủ yếu là một nhà phát triển C # và đó là quy ước thường được chấp nhận. Không có lý do khác.
RubberDuck

6
@Rouletteifficas là một bổ sung, những gì bạn gọi là LowerCase nhưng chứa một chữ hoa ở giữa thường được gọi là camelCase, bởi vì nó có bướu ở giữa. Điều đó phân biệt nó với Snake_case, trong đó các từ viết thường được phân tách bằng dấu gạch dưới, vốn quen thuộc với python và hầu hết các ngôn ngữ shell, để đặt tên cho một số.
Aaron

5
Sự kiện là một loại của những tin nhắn này, tôi muốn nói. Các cuộc gọi phương thức cũng được coi là chuyển tin nhắn.
jpmc26

53

Không.

Một ví dụ kinh điển về các sự kiện đang được sử dụng trong logic phi GUI là các trình kích hoạt cơ sở dữ liệu.

Kích hoạt là mã được thực thi khi một sự kiện nhất định xảy ra (CHERTN, XÓA, v.v.). Có vẻ như một sự kiện với tôi.

Đây là định nghĩa Wikipedia về sự kiện:

Trong điện toán, một sự kiện là một hành động hoặc sự cố được công nhận bởi phần mềm có thể được xử lý bởi phần mềm. Các sự kiện máy tính có thể được tạo hoặc kích hoạt bởi hệ thống, bởi người dùng hoặc theo những cách khác. Thông thường, các sự kiện được xử lý đồng bộ với luồng chương trình, nghĩa là phần mềm có thể có một hoặc nhiều nơi dành riêng cho các sự kiện được xử lý, thường là một vòng lặp sự kiện. Một nguồn sự kiện bao gồm người dùng, người có thể tương tác với phần mềm bằng cách, ví dụ, tổ hợp phím trên bàn phím. Một nguồn khác là một thiết bị phần cứng như bộ đếm thời gian. Phần mềm cũng có thể kích hoạt tập hợp các sự kiện của riêng nó vào vòng lặp sự kiện, ví dụ để truyền đạt việc hoàn thành một nhiệm vụ. Phần mềm thay đổi hành vi của nó để đáp ứng với các sự kiện được cho là hướng đến sự kiện, thường với mục tiêu là tương tác.

Không phải tất cả các sự kiện là do người dùng tạo ra. Một số được tạo bởi một bộ đếm thời gian như một crontab của cơ sở dữ liệu INSERT như tôi đã đề cập trước đó.

Định nghĩa cũng nêu rõ hơn một số chương trình hoặc hệ thống là "hướng sự kiện, thường với mục tiêu là tương tác" , từ đó người ta có thể rút ra rằng mục đích hoặc tính hữu ích của các sự kiện không chỉ, mà thường là, để cung cấp tính tương tác (như GUI mặc dù không nhất thiết phải là GUI, vì các chương trình CLI cũng có thể tương tác).


2
Tôi luôn nghĩ về điều này khi tôi nghe về các kích hoạt cơ sở dữ liệu: thecodlesscode.com/case/42
Almo

Là một nhà phát triển DBA hiện tại, tôi co rúm mỗi khi nghe mọi người nói về việc sử dụng các kích hoạt mà không xem xét hiệu suất DB rộng hơn.
Ba logic giá trị

27

Lập trình dựa trên sự kiện thực sự cũng được sử dụng cho lập trình máy chủ có hiệu suất cao.

Ở một khối lượng công việc máy chủ thông thường, phần lớn thời gian xử lý một kết quả thực sự đến từ I / O. Ví dụ, kéo dữ liệu ra khỏi ổ đĩa cứng (7200 RPM) có thể mất tới 8,3 ms. Đối với bộ xử lý GHz hiện đại, điều đó sẽ tương đương với ~ 1 triệu chu kỳ xung nhịp. Nếu CPU phải đợi dữ liệu mỗi lần (không làm gì), chúng ta sẽ mất rất nhiều chu kỳ xung nhịp.

Các kỹ thuật lập trình truyền thống có được xung quanh điều này bằng cách giới thiệu nhiều chủ đề . CPU cố gắng chạy hàng trăm luồng đồng thời. Tuy nhiên, vấn đề mà mô hình này là, mỗi lần CPU chuyển luồng, nó đòi hỏi hàng trăm chu kỳ xung nhịp để chuyển đổi ngữ cảnh . Chuyển đổi ngữ cảnh là khi CPU sao chép bộ nhớ cục bộ của luồng vào các thanh ghi của CPU và cũng lưu trữ thanh ghi / trạng thái của luồng cũ vào RAM.

Ngoài ra, mỗi luồng phải sử dụng một lượng bộ nhớ nhất định để lưu trữ trạng thái của nó.

Ngày nay, đã có một sự thúc đẩy cho các máy chủ có một luồng duy nhất, chạy trong một vòng lặp. Sau đó, các phần công việc được đẩy lên một bơm thông báo , hoạt động như một hàng đợi cho một luồng (giống như trên một luồng UI). Thay vì chờ công việc kết thúc, CPU sẽ đặt một sự kiện gọi lại, cho những thứ như truy cập ổ đĩa cứng. Làm giảm chuyển đổi ngữ cảnh.

Ví dụ tốt nhất về một máy chủ như vậy là Node.js , được chứng minh là có thể xử lý 1 triệu kết nối đồng thời với phần cứng khiêm tốn, trong khi máy chủ Java / Tomcat sẽ gặp khó khăn ở mức vài nghìn.


2
"Phần cứng khiêm tốn" là một chút sai lệch. Bạn sẽ cần 8GB + cho Node, ngoài bất kỳ hệ điều hành nào sử dụng. Và nếu bạn có nhiều bộ nhớ đó, Tomcat có thể dễ dàng xử lý vài nghìn kết nối. Cấp, có một sự khác biệt lớn, nhưng nó không phải là 1000 lần.
Paul Draper

@PaulDraper không nó không thể. Và không, nó không có. Bạn cần 8GB + cho chỉ stack cho 8000 chủ đề. Đó là sự khác biệt lớn.
ArTs

3
@PaulDraper ngoài 8GB rất khiêm tốn theo tiêu chuẩn máy chủ. Tôi đã làm việc trên các máy có 128GB ram và những máy này thậm chí không được tải đầy đủ. Các thanh ram có giá cao hơn toàn bộ máy của bạn.
ArTs

nó phụ thuộc vào kích thước ngăn xếp của bạn là gì. Oracle / OpenJDK mặc định là 1MB trên hầu hết các nền tảng cho 64 bit và 512K cho 32 bit. Nếu bạn chỉ mặc định, bạn sẽ đúng. Nhưng mặc định không phải là cách bạn có được kết nối Node 1M;) Dù sao, 128K là rất nhiều; bạn có thể đi với thậm chí ít hơn. Đó sẽ là 1GB dung lượng ngăn xếp cho 8000 luồng.
Paul Draper

6
Bạn đang nhầm. Ngay cả với kích thước ngăn xếp mặc định, bạn chỉ cần 8 GiB bộ nhớ ảo . Bộ nhớ được cam kết trên bay khi cần thiết. Thông thường, bạn chỉ cần một trang duy nhất cho mỗi ngăn xếp, trừ khi bạn thực sự sử dụng bộ nhớ thêm. Và trong thực tế, hầu hết các luồng trong một hệ thống như vậy chỉ có các ngăn 64-kiB (thường). Sử dụng bộ nhớ ảo là một vấn đề lớn trên HĐH 32 bit, nhưng không nhiều trên 64 bit. Bạn chạy vào các giới hạn khác sớm hơn nhiều - chẳng hạn như cạn kiệt cổng TCP :) Và bạn nghĩ những "ngăn xếp giả" đó của nút được lưu trữ ở đâu? Đúng vậy, trên đống.
Luaan

10

Các sự kiện cũng được sử dụng nhiều trong lập trình mạng (ví dụ Nginx) để tránh các vòng lặp bận rộn đắt tiền và thay vào đó cung cấp giao diện sạch để biết chính xác khi nào có một hoạt động nhất định (I / O, dữ liệu khẩn cấp, v.v.). Đây cũng là một giải pháp cho vấn đề C10k .

Ý tưởng cơ bản là cung cấp cho HĐH một bộ ổ cắm (ví dụ: kết nối mạng) để theo dõi các sự kiện, tất cả chúng hoặc chỉ một số bạn đặc biệt quan tâm (ví dụ: dữ liệu có sẵn để đọc); Khi hệ điều hành được phát hiện bởi một trong các ổ cắm trong danh sách, bạn sẽ nhận được thông báo về sự kiện mà bạn đang tìm kiếm bởi API, sau đó bạn sẽ phải sắp xếp nó đến từ đâu và hành động phù hợp .

Bây giờ, đây là một cái nhìn cấp thấp và trừu tượng, hơn nữa khó khăn để có được quy mô tốt. Tuy nhiên, có rất nhiều khung công tác cấp cao hơn giải quyết vấn đề đó theo kiểu đa nền tảng: Twisted for Python, Boost.Asio cho C ++ hoặc libevent cho C xuất hiện trong tâm trí tôi.


+1 "vòng lặp bận rộn chờ đợi đắt tiền": nói cách khác, nó hữu ích trong mọi quy trình song song liên quan đến một số hoạt động (chờ), cũng như đồng bộ hóa giữa các quy trình đó (tin nhắn hoặc sự kiện). Như nhiều thế giới thực hoạt động.
fr13d

Thật thú vị khi tìm ra rằng các ổ cắm ban đầu được thiết kế như một dạng IPC trên một máy duy nhất, trước khi mạng tồn tại.

5

Các hệ thống nhúng hầu như luôn luôn hướng đến sự kiện, ngay cả khi chúng không được lập trình rõ ràng như vậy.

Những sự kiện này đến từ những thứ như gián đoạn phần cứng, nhấn nút, đọc thời gian tương tự sang số, hết hạn hẹn giờ, v.v.

Các hệ thống nhúng công suất thấp thậm chí có nhiều khả năng được điều khiển theo sự kiện; họ dành phần lớn thời gian để ngủ (CPU ngủ ở chế độ năng lượng thấp), chờ đợi điều gì đó xảy ra ("cái gì đó" là một sự kiện).

Một trong những khung phổ biến và phổ biến nhất cho các hệ thống nhúng theo hướng sự kiện là Nền tảng lượng tử (QP) (QP cũng hoạt động trong Linux, Windows và bất kỳ HĐH nào giống như máy chủ.) vì chương trình không phải là "tuần tự" theo nghĩa thông thường, thay vào đó, nó là một tập hợp các "cuộc gọi lại" được gọi tùy thuộc vào trạng thái hệ thống và sự kiện hiện tại.


3

Tin nhắn sự kiện Gregor Hohpe.

Kiến trúc hướng sự kiện Gregor Hohpe.

Kiến trúc SEDA , tiếng Wales, Culler, nhà sản xuất bia.

Làm thế nào để bạn xử lý trong lập trình phụ trợ bình thường khi một cái gì đó xảy ra làm điều này khác?

Máy trạng thái hữu hạn là một cách tiếp cận phổ biến

Given(State.A)
When(Event.B)
Then(State.C)
    .and(Consequences.D)

2
1, đây không thực sự là một câu trả lời mạch lạc và 2, FSM không phải là ví dụ điển hình cho việc sử dụng sự kiện.
whatsisname

1
FSM. Tôi chắc rằng tôn giáo của người quá khứ quan sát một số sự kiện ;-)
fr13d

0

Trong các hệ thống nhúng, các sự kiện xảy ra trong quá trình ngắt. Có nhiều nguồn ngắt, từ bộ định thời đến I / O.

Ngoài ra, RTOS cũng có thể có các sự kiện. Một ví dụ là chờ tin nhắn từ một nhiệm vụ khác.


0

Đối với hệ thống không nhúng nhưng thứ tôi đang làm trong C # là hệ thống SCADA. Có nhiều sự kiện liên quan đến những gì đã xảy ra trong kho khi tải được tải một phần của sự kiện do hệ thống tạo ra và phần khác đang ghi trạng thái mới vào cơ sở dữ liệu. Tất nhiên chúng tôi có một số máy khách GUI nhưng nó chỉ hiển thị trạng thái của cơ sở dữ liệu phản ánh trạng thái của kho. Vì vậy, nó là phần mềm máy chủ phụ trợ dựa trên các sự kiện và phân luồng. Khá thách thức để phát triển.

https://en.wikipedia.org/wiki/SCADA

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.