Vòng lặp sự kiện Python

Mọi người xây dựng vòng lặp sự kiện để hiểu và mô tả nó hoạt động như thế nào. Điều đó thật tuyệt. Tôi cũng muốn hiểu nó. Vì vậy, tôi quyết định làm một cái… Một cái giả… Như mọi người vẫn làm… Nhưng điều tôi muốn chỉ ra — đó là hàng giả

Vòng lặp sự kiện là gì?

Vòng lặp sự kiện là một cấu trúc lập trình được xử lý tự do và là công cụ đầu mối cho chính chương trình co-op và đồng thời. Nhưng nó phát triển đúng nghĩa khi nó được sử dụng để xây dựng các chương trình không đồng bộ. Vì lý do đó, tôi coi bất kỳ dạng vòng lặp sự kiện nào không thể được sử dụng để xây dựng sự không đồng bộ - giả mạo

Vòng lặp sự kiện chờ và gửi các sự kiện hoặc thông báo trong một chương trình. Nó hoạt động bằng cách gửi yêu cầu tới một số “nhà cung cấp sự kiện” bên trong hoặc bên ngoài (thường chặn yêu cầu cho đến khi một sự kiện đến), sau đó nó gọi trình xử lý sự kiện có liên quan (“gửi sự kiện”)

Vòng lặp sự kiện là một giải pháp cho một vấn đề logic cổ điển “Các nhà triết học ăn uống”

Năm triết gia im lặng ngồi quanh chiếc bàn tròn với bát mì spaghetti. Dĩa được đặt giữa mỗi cặp triết gia liền kề

Mỗi triết gia phải luân phiên nghĩ và ăn. Tuy nhiên, một triết gia chỉ có thể ăn spaghetti khi họ có cả nĩa trái và nĩa phải. Mỗi chiếc nĩa chỉ có thể được giữ bởi một triết gia và vì vậy một triết gia chỉ có thể sử dụng chiếc nĩa nếu nó không được sử dụng bởi một triết gia khác. Sau khi một triết gia cá nhân ăn xong, họ cần đặt cả hai chiếc nĩa xuống để những chiếc nĩa đó dành cho người khác

Vòng lặp sự kiện đồng tình với một phần thứ tự thu được tài nguyên được chia sẻ và gửi sự kiện. Trong vấn đề, các nhánh được chia sẻ tài nguyên, các nhà triết học đang thu thập các quy trình, cảm giác no và mong muốn suy nghĩ là các sự kiện được sử dụng để đồng tình và cân bằng việc sử dụng tài nguyên

vòng lặp chính xác

Dưới đây là một vòng lặp sự kiện. Nó có thể giúp hiểu mức độ không đồng bộ có thể xảy ra nhưng ở trạng thái hiện tại, nó không thể thực hiện được

tasks = {"-=* BOOM *=-": 2, "~=* shaka *=~": 1}

nhiệm vụ. Trong các tác vụ vòng lặp sự kiện thực được tạo từ các sự kiện/thông báo đến từ quy trình bên ngoài. Trong triển khai giả, các tác vụ là hằng số và được trình bày mãi mãi bên trong vòng lặp

if not in_action:
in_action = [
coro(sound, delay) for sound, delay in tasks.items()
]

Các tác vụ thực tế sẽ được xử lý trong vòng lặp sự kiện. Các nhiệm vụ gần như có thật từ quan điểm đó. Một tác vụ sẽ được xử lý tương ứng với các sự kiện mà nó tạo ra. Bản thân vòng lặp không quan tâm đến tính toán trong các nhiệm vụ hoặc mối quan hệ của nhiệm vụ với thế giới bên ngoài, nó chỉ quan tâm đến các sự kiện. Một sự khác biệt là trong thực hiện nhiệm vụ

task = in_action.pop(0)

Nhận nhiệm vụ để xử lý. Trong vòng lặp cụ thể này, tôi nhận nhiệm vụ tiếp theo một cách mù quáng. Trong chương trình thực, chúng ta có thể có thông tin bổ sung về các sự kiện trước đó và ví dụ: xử lý các tác vụ bằng cách sử dụng dữ liệu này. Không có sự khác biệt chính

dl = task.send(None)

nhiệm vụ thức. Dòng này kết hợp một số mục đích. Lúc đầu, đây là lệnh gọi trình xử lý tác vụ dẫn đến kết quả tính toán tác vụ cuối cùng. Ngoài ra, nó nhận được một phần kết quả tính toán ở mỗi lần lặp. Và cuối cùng là xử lý sự kiện task. Chúng tôi có hai sự kiện 'sẵn sàng' và 'đang diễn ra'. Khi một tác vụ đang được tiến hành, chỉ có kết quả trung gian (dữ liệu meta) sẽ được lấy từ đối tượng có thể chờ đợi. Nếu tác vụ 'sẵn sàng' thì lỗi StopIteration sẽ xuất hiện và giá trị kết quả sẽ có sẵn trong đó. Trong triển khai giả mạo của chúng tôi, không có tính toán nào tồn tại đằng sau tác vụ. Kết quả tính toán trung gian chỉ được sử dụng để duy trì quá trình tạo tác vụ vô hạn (độ trễ ban đầu được sử dụng để tạo tác vụ tương tự khi tác vụ được thực hiện). Hệ thống sự kiện cũng được đơn giản hóa — “sẵn sàng” và “đang tiến hành” có thể là không đủ, mỗi phép tính trung gian có thể mang lại các sự kiện khác nhau

in_action.append(coro(e.value, tasks[e.value]))

Vòng lặp là vô hạn nên một nhiệm vụ mới có cùng đối số sẽ được thêm vào khi hoàn thành một nhiệm vụ

in_action.append(task)

Đưa các nhiệm vụ “đang tiến hành” trở lại vòng lặp

Sự khác biệt đầu mối

coro coroutine đang đợi từ một thể hiện của đối tượng có thể chờ đợi của Delay. Không có tính toán. Ngoài ra, đường ống không giao tiếp với các quy trình bên ngoài. Nhưng cả hai bước của quy trình đều cẩn thận giả vờ không đồng bộ bằng cách sử dụng tính năng chính của coroutines - trạng thái tạm dừng. Chuỗi hệ điều hành là tài nguyên được chia sẻ cho tất cả các tác vụ đã bắt đầu. Vì vậy, nếu để thực hiện bất kỳ tính toán nào (thao tác chặn) bên trong các tác vụ, nó sẽ mất chính xác thời gian như nhau bất kể nó được thực hiện theo thứ tự nghiêm ngặt hay theo thứ tự một phần. Tổng là như nhau bất kể bạn nhóm các số như thế nào. Nó có vô ích không? . Không nếu thời gian giữa các lần nhận được kết quả cuối cùng là quan trọng

Hiểu về sự không đồng bộ

Trong vòng lặp, chúng tôi đã không triển khai tính không đồng bộ thực sự (hữu ích) nhưng có sự đồng thời giúp chúng tôi hiểu cách thức hoạt động của tính không đồng bộ

Chúng tôi đang trả tiền với thời gian ở đây. Và thời gian là chung cho mỗi nhiệm vụ trong vòng lặp. Xác định độ trễ theo số tuyệt đối (giây) cho mỗi tác vụ, chúng ta có thể thao tác với các tác vụ tương ứng với thời điểm hiện tại vì cả hai bước của đường ống đều có thể tạm dừng trạng thái của nó. Phiên bản Delay sẽ được lưu giữ trong coro cho đến khi coro trả lại. Thời gian của sự kiện 'sẵn sàng' sẽ được giữ bởi đối tượng có thể chờ đợi của Delay cho đến khi nó trở thành hiện thực. Vì vậy, mỗi nhiệm vụ đã dành chính xác thời gian nhất định (trong đối số

if not in_action:
in_action = [
coro(sound, delay) for sound, delay in tasks.items()
]
3) để chờ đợi nhưng các nhiệm vụ đã dành những khoảng thời gian này đồng thời nhưng không mạch lạc

Vì vậy, đây là sự không đồng bộ giữa nhiệm vụ và thời gian. Thời gian là chung, khách quan và tạo ra các sự kiện cho các nhiệm vụ

Điều gì còn thiếu để triển khai tính không đồng bộ hữu ích?

  • Thao tác chặn phải được thực hiện trong (các) quy trình khác nhau. Đây là sự không đồng bộ giữa bộ lập lịch tác vụ co-op và các quy trình tính toán độc lập (theo nghĩa rộng)
  • Các sự kiện từ các quy trình này phải được cung cấp bằng cách sử dụng các công cụ liên lạc giữa các quy trình — non-blocking sockets
  • Ngoài ra, các tác vụ có thể được cung cấp bởi nguồn sự kiện/tin nhắn bên ngoài vòng lặp. (Mô hình lò phản ứng)

Phần kết luận

Thật tốt khi hiểu đồng thời và không đồng bộ bằng các ví dụ thực tế đơn giản. Nhưng đừng tin vào sự cường điệu, các chương trình không đồng bộ thực sự phức tạp hơn và sử dụng nhiều công cụ hơn vòng lặp sự kiện trần. Mặc dù sự hiểu biết về bản chất hợp tác của vòng lặp sự kiện làm cho sự hiểu biết về sự không đồng bộ trở thành một kết quả thấp

Vòng lặp sự kiện Python là gì?

Vòng lặp sự kiện là cốt lõi của mọi ứng dụng asyncio . Các vòng lặp sự kiện chạy các tác vụ và lệnh gọi lại không đồng bộ, thực hiện các hoạt động IO của mạng và chạy các quy trình con. Các nhà phát triển ứng dụng thường nên sử dụng các chức năng asyncio cấp cao, chẳng hạn như asyncio.

Python có sử dụng vòng lặp sự kiện không?

Vòng lặp sự kiện Python là trung tâm của mỗi ứng dụng asyncio . Vòng kết nối sự kiện, chạy các nhiệm vụ và lệnh gọi lại khác thường, thực hiện sắp xếp các hoạt động IO và chạy các quy trình con. Vòng lặp sự kiện Python rất hữu ích để xử lý tất cả các trường hợp trong mã tính toán.

Vòng lặp sự kiện hoạt động như thế nào?

Vòng lặp sự kiện có một công việc đơn giản — để giám sát Ngăn xếp cuộc gọi và Hàng đợi gọi lại . Nếu Ngăn xếp cuộc gọi trống, Vòng lặp sự kiện sẽ lấy sự kiện đầu tiên từ hàng đợi và sẽ đẩy nó vào Ngăn xếp cuộc gọi, nơi sẽ chạy nó một cách hiệu quả. Một lần lặp lại như vậy được gọi là đánh dấu trong Vòng lặp sự kiện.

Sự chờ đợi có chặn vòng lặp sự kiện Python không?

Từ khóa await chuyển điều khiển chức năng trở lại vòng lặp sự kiện . (Nó tạm dừng việc thực thi coroutine xung quanh. ) Nếu Python gặp một biểu thức await f() trong phạm vi của g() , thì đây là cách await báo cho vòng lặp sự kiện, “Tạm dừng thực thi g() cho đến khi tôi đang đợi bất cứ thứ gì—kết quả của f() —là .