Python gọi chức năng async từ đồng bộ hóa
Bạn đã nghe nói về lập trình không đồng bộ trong Python chưa? . Nếu bạn đang tìm hiểu cách sử dụng các tính năng không đồng bộ của Python, thì bạn đã đến đúng nơi Show
Trong bài viết này, bạn sẽ học
Tất cả các mã ví dụ trong bài viết này đã được thử nghiệm với Python 3. 7. 2. Bạn có thể lấy một bản sao để theo dõi bằng cách nhấp vào liên kết bên dưới Tải xuống mã. Nhấp vào đây để tải xuống mã mà bạn sẽ sử dụng để tìm hiểu về các tính năng không đồng bộ trong Python trong hướng dẫn này Hiểu lập trình không đồng bộMột chương trình đồng bộ được thực hiện từng bước một. Ngay cả với các lệnh gọi hàm, vòng lặp và phân nhánh có điều kiện, bạn vẫn có thể nghĩ về mã theo cách thực hiện từng bước thực hiện tại một thời điểm. Khi mỗi bước hoàn thành, chương trình sẽ chuyển sang bước tiếp theo Dưới đây là hai ví dụ về các chương trình hoạt động theo cách này
Một chương trình không đồng bộ hoạt động khác nhau. Nó vẫn mất một bước thực hiện tại một thời điểm. Sự khác biệt là hệ thống có thể không đợi một bước thực hiện hoàn thành trước khi chuyển sang bước tiếp theo Điều này có nghĩa là chương trình sẽ chuyển sang các bước thực hiện trong tương lai mặc dù bước trước đó chưa kết thúc và vẫn đang chạy ở nơi khác. Điều này cũng có nghĩa là chương trình biết phải làm gì khi bước trước chạy xong Tại sao bạn muốn viết một chương trình theo cách này? Loại bỏ các quảng cáoXây dựng một máy chủ web đồng bộĐơn vị công việc cơ bản của máy chủ web ít nhiều cũng giống như xử lý hàng loạt. Máy chủ sẽ nhận một số đầu vào, xử lý nó và tạo đầu ra. Được viết dưới dạng chương trình đồng bộ, điều này sẽ tạo ra một máy chủ web đang hoạt động Nó cũng sẽ là một máy chủ web hoàn toàn khủng khiếp Tại sao? . Mục đích thực sự là xử lý hàng trăm, thậm chí hàng nghìn đơn vị công việc nhanh nhất có thể. Điều này có thể xảy ra trong thời gian dài và thậm chí một số đơn vị công việc có thể đến cùng một lúc Một máy chủ web đồng bộ có thể được thực hiện tốt hơn? . Thật không may, có những hạn chế đối với phương pháp này. Kết quả có thể là một máy chủ web không phản hồi đủ nhanh, không thể xử lý đủ công việc hoặc thậm chí là một máy chủ hết thời gian chờ khi công việc chồng chất lên nhau Ghi chú. Có những hạn chế khác mà bạn có thể thấy nếu cố gắng tối ưu hóa phương pháp trên. Chúng bao gồm tốc độ mạng, tốc độ tệp IO, tốc độ truy vấn cơ sở dữ liệu và tốc độ của các dịch vụ được kết nối khác, v.v. Tất cả những thứ này đều có điểm chung là chúng đều là các hàm IO. Tất cả các mục này đều chậm hơn so với tốc độ xử lý của CPU Trong một chương trình đồng bộ, nếu một bước thực hiện bắt đầu một truy vấn cơ sở dữ liệu, thì về cơ bản, CPU sẽ không hoạt động cho đến khi truy vấn cơ sở dữ liệu được trả về. Đối với các chương trình định hướng hàng loạt, đây không phải là ưu tiên trong hầu hết thời gian. Xử lý kết quả của hoạt động IO đó là mục tiêu. Thông thường, quá trình này có thể mất nhiều thời gian hơn chính thao tác IO. Mọi nỗ lực tối ưu hóa sẽ được tập trung vào công việc xử lý, không phải IO Các kỹ thuật lập trình không đồng bộ cho phép các chương trình của bạn tận dụng các quy trình IO tương đối chậm bằng cách giải phóng CPU để thực hiện công việc khác Nghĩ khác về lập trìnhKhi bạn bắt đầu cố gắng hiểu lập trình không đồng bộ, bạn có thể thấy rất nhiều cuộc thảo luận về tầm quan trọng của việc chặn hoặc viết mã không chặn. (Cá nhân tôi gặp khó khăn trong việc nắm bắt tốt các khái niệm này từ những người tôi đã hỏi và tài liệu tôi đọc. ) Mã không chặn là gì? Viết chương trình không đồng bộ đòi hỏi bạn phải nghĩ khác về lập trình. Mặc dù cách suy nghĩ mới này có thể khiến bạn khó hiểu, nhưng đây cũng là một bài tập thú vị. Đó là bởi vì thế giới thực gần như hoàn toàn không đồng bộ và cách bạn tương tác với nó cũng vậy. Hãy tưởng tượng điều này. bạn là cha mẹ đang cố gắng làm nhiều việc cùng một lúc. Bạn phải cân bằng sổ séc, giặt giũ và để mắt đến bọn trẻ. Bằng cách nào đó, bạn có thể làm tất cả những việc này cùng một lúc mà không cần suy nghĩ về nó. Hãy phá vỡ nó
Những ví dụ này có thể giúp minh họa các khái niệm về mã chặn và mã không chặn. Hãy nghĩ về điều này trong thuật ngữ lập trình. Trong ví dụ này, bạn giống như CPU. Trong khi bạn đang di chuyển đồ giặt xung quanh, bạn (CPU) đang bận và bị chặn làm công việc khác, chẳng hạn như cân bằng sổ séc. Nhưng không sao vì nhiệm vụ tương đối nhanh Mặt khác, việc khởi động máy giặt và máy sấy không cản trở bạn thực hiện các tác vụ khác. Đây là một chức năng không đồng bộ vì bạn không phải đợi nó hoàn thành. Sau khi nó bắt đầu, bạn có thể quay lại thứ khác. Đây được gọi là chuyển đổi ngữ cảnh. bối cảnh công việc bạn đang làm đã thay đổi và chuông của máy sẽ thông báo cho bạn trong tương lai khi nhiệm vụ giặt là hoàn tất Là một con người, đây là cách bạn làm việc mọi lúc. Bạn làm nhiều việc cùng một lúc một cách tự nhiên mà không cần suy nghĩ về nó. Là một nhà phát triển, mẹo là làm thế nào để chuyển loại hành vi này thành mã thực hiện cùng loại cha mẹ lập trình. Không dễ như bề ngoàiNếu bạn nhận ra chính mình (hoặc cha mẹ của bạn) trong ví dụ trên thì thật tuyệt. Bạn đã hiểu rõ hơn về lập trình không đồng bộ. Một lần nữa, bạn có thể chuyển ngữ cảnh giữa các tác vụ cạnh tranh khá dễ dàng, chọn một số tác vụ và tiếp tục các tác vụ khác. Bây giờ bạn sẽ thử và lập trình hành vi này thành cha mẹ ảo Thử nghiệm suy nghĩ #1. Cha mẹ đồng bộBạn sẽ tạo một chương trình mẹ như thế nào để thực hiện các tác vụ trên một cách hoàn toàn đồng bộ? . Cha mẹ trông chừng con cái trong khi chờ đợi điều gì đó xảy ra có thể cần sự chú ý của chúng. Tuy nhiên, không có gì khác (như sổ séc hoặc đồ giặt) sẽ được thực hiện trong tình huống này Giờ đây, bạn có thể sắp xếp lại mức độ ưu tiên cho các nhiệm vụ theo bất kỳ cách nào bạn muốn, nhưng chỉ một trong số chúng sẽ xảy ra vào bất kỳ thời điểm nào. Đây là kết quả của cách làm đồng bộ, từng bước. Giống như máy chủ web đồng bộ được mô tả ở trên, điều này sẽ hoạt động, nhưng nó có thể không phải là cách tốt nhất để tồn tại. Cha mẹ sẽ không thể hoàn thành bất kỳ nhiệm vụ nào khác cho đến khi bọn trẻ ngủ thiếp đi. Tất cả các nhiệm vụ khác sẽ xảy ra sau đó, vào ban đêm. (Một vài tuần như vậy và nhiều bậc cha mẹ thực sự có thể nhảy ra khỏi cửa sổ. ) Loại bỏ các quảng cáoThử nghiệm suy nghĩ #2. Cha mẹ thăm dò ý kiếnNếu bạn đã sử dụng tính năng bỏ phiếu, thì bạn có thể thay đổi mọi thứ để hoàn thành nhiều tác vụ. Theo cách tiếp cận này, cha mẹ sẽ định kỳ thoát khỏi nhiệm vụ hiện tại và kiểm tra xem có nhiệm vụ nào khác cần chú ý không. Hãy tạo khoảng thời gian bỏ phiếu giống như mười lăm phút. Bây giờ, cứ sau mười lăm phút, cha mẹ của bạn sẽ kiểm tra xem máy giặt, máy sấy hoặc trẻ em có cần chú ý gì không. Nếu không, phụ huynh có thể quay lại làm việc trên sổ séc. Tuy nhiên, nếu bất kỳ nhiệm vụ nào trong số đó cần chú ý, thì phụ huynh sẽ quan tâm đến việc đó trước khi quay lại sổ séc. Chu kỳ này tiếp tục cho đến khi hết thời gian chờ tiếp theo của vòng bỏ phiếu Cách tiếp cận này cũng hiệu quả vì nhiều nhiệm vụ đang được chú ý. Tuy nhiên, có một vài vấn đề
Bạn có thể giải quyết những vấn đề này bằng cách rút ngắn khoảng thời gian bỏ phiếu, nhưng bây giờ cha mẹ của bạn (CPU) sẽ dành nhiều thời gian hơn để chuyển ngữ cảnh giữa các tác vụ. Đây là khi bạn bắt đầu đạt đến điểm lợi nhuận giảm dần. (Một lần nữa, một vài tuần sống như thế này và, chà… Xem bình luận trước về cửa sổ và nhảy. ) Thử nghiệm suy nghĩ #3. Cha mẹ luồng“Giá như tôi có thể nhân bản chính mình…” Nếu là cha mẹ, chắc hẳn bạn cũng từng có suy nghĩ tương tự. Vì bạn đang lập trình cha mẹ ảo, nên về cơ bản, bạn có thể thực hiện việc này bằng cách sử dụng phân luồng. Đây là cơ chế cho phép nhiều phần của một chương trình chạy cùng lúc. Mỗi phần mã chạy độc lập được gọi là một luồng và tất cả các luồng chia sẻ cùng một không gian bộ nhớ Nếu bạn coi mỗi tác vụ là một phần của một chương trình, thì bạn có thể tách chúng ra và chạy chúng dưới dạng các luồng. Nói cách khác, bạn có thể “sao chép” cha mẹ, tạo một phiên bản cho mỗi tác vụ. theo dõi lũ trẻ, giám sát máy giặt, giám sát máy sấy và cân bằng sổ séc. Tất cả những “bản sao” này đang chạy độc lập Điều này nghe có vẻ là một giải pháp khá hay, nhưng cũng có một số vấn đề ở đây. Một là bạn sẽ phải thông báo rõ ràng cho từng cá thể mẹ phải làm gì trong chương trình của mình. Điều này có thể dẫn đến một số vấn đề vì tất cả các phiên bản đều chia sẻ mọi thứ trong không gian chương trình Ví dụ: giả sử Phụ huynh A đang giám sát máy sấy. Phụ huynh A thấy quần áo đã khô nên điều khiển máy sấy và bắt đầu lấy quần áo ra. Cùng lúc đó, Phụ huynh B thấy máy giặt đã xong nên điều khiển máy giặt và bắt đầu lấy quần áo ra. Tuy nhiên, Phụ huynh B cũng cần kiểm soát máy sấy để cho quần áo ướt vào bên trong. Điều này không thể xảy ra vì Phụ huynh A hiện đang có quyền kiểm soát máy sấy Một lúc sau, phụ huynh A đã dỡ xong quần áo. Bây giờ họ muốn kiểm soát máy giặt và bắt đầu chuyển quần áo vào máy sấy trống. Điều này cũng không thể xảy ra vì Phụ huynh B hiện có quyền kiểm soát máy giặt Hai bố mẹ này giờ đã. Cả hai đều có quyền kiểm soát tài nguyên của mình và muốn kiểm soát tài nguyên khác. Họ sẽ đợi mãi cho đến khi phiên bản gốc khác giải phóng quyền kiểm soát. Là lập trình viên, bạn phải viết mã để giải quyết tình huống này Ghi chú. Các chương trình theo luồng cho phép bạn tạo nhiều đường dẫn thực thi song song, tất cả đều chia sẻ cùng một không gian bộ nhớ. Đây vừa là ưu điểm vừa là nhược điểm. Mọi bộ nhớ được chia sẻ giữa các luồng đều phải tuân theo một hoặc nhiều luồng đang cố gắng sử dụng cùng một bộ nhớ được chia sẻ cùng một lúc. Điều này có thể dẫn đến hỏng dữ liệu, đọc dữ liệu ở trạng thái không hợp lệ và dữ liệu nói chung là lộn xộn Trong lập trình luồng, chuyển đổi ngữ cảnh xảy ra dưới sự kiểm soát của hệ thống, không phải lập trình viên. Hệ thống kiểm soát thời điểm chuyển ngữ cảnh và thời điểm cấp quyền truy cập cho các luồng vào dữ liệu được chia sẻ, do đó thay đổi ngữ cảnh về cách bộ nhớ đang được sử dụng. Tất cả các loại sự cố này đều có thể quản lý được trong mã luồng, nhưng rất khó để hiểu đúng và khó gỡ lỗi khi sai Đây là một vấn đề khác có thể phát sinh từ luồng. Giả sử một đứa trẻ bị thương và cần được đưa đi cấp cứu. Phụ huynh C được giao nhiệm vụ trông con nên đưa con đi ngay. Tại phòng chăm sóc khẩn cấp, Phụ huynh C cần viết một tấm séc khá lớn để trang trải chi phí gặp bác sĩ Trong khi đó, phụ huynh D ở nhà làm sổ sách chi phiếu. Họ không biết tấm séc lớn này được viết, vì vậy họ rất ngạc nhiên khi tài khoản séc của gia đình đột nhiên bị thấu chi. Hãy nhớ rằng, hai phiên bản gốc này đang hoạt động trong cùng một chương trình. Tài khoản séc của gia đình là tài nguyên được chia sẻ, vì vậy bạn phải tìm ra cách để phụ huynh trông trẻ thông báo cho phụ huynh đang cân đối sổ séc. Mặt khác, bạn cần cung cấp một số loại cơ chế khóa để tài nguyên sổ séc chỉ có thể được sử dụng bởi một phụ huynh tại một thời điểm, với các bản cập nhật Sử dụng các tính năng không đồng bộ của Python trong thực tếBây giờ, bạn sẽ thực hiện một số cách tiếp cận được nêu trong các thử nghiệm tưởng tượng ở trên và biến chúng thành các chương trình Python hoạt động được Tất cả các ví dụ trong bài viết này đã được thử nghiệm với Python 3. 7. 2. Tệp 2 cho biết bạn sẽ cần cài đặt mô-đun nào để chạy tất cả các ví dụ. Nếu bạn chưa tải xuống tệp, bạn có thể thực hiện ngay bây giờTải xuống mã. Nhấp vào đây để tải xuống mã mà bạn sẽ sử dụng để tìm hiểu về các tính năng không đồng bộ trong Python trong hướng dẫn này Bạn cũng có thể muốn thiết lập môi trường ảo Python để chạy mã để bạn không can thiệp vào Python hệ thống của mình Loại bỏ các quảng cáoLập trình đồng bộVí dụ đầu tiên này cho thấy một cách có phần giả tạo để có một tác vụ truy xuất công việc từ một hàng đợi và xử lý công việc đó. Một hàng đợi trong Python là một cấu trúc dữ liệu FIFO (vào trước ra trước) đẹp. Nó cung cấp các phương thức để đặt mọi thứ vào hàng đợi và lấy chúng ra một lần nữa theo thứ tự chúng được đưa vào Trong trường hợp này, công việc là lấy một số từ hàng đợi và có một vòng lặp đếm đến số đó. Nó in ra bàn điều khiển khi vòng lặp bắt đầu và một lần nữa để xuất tổng số. Chương trình này trình bày một cách để nhiều tác vụ đồng bộ xử lý công việc trong hàng đợi Chương trình có tên 3 trong kho lưu trữ được liệt kê đầy đủ bên dưới
Hãy xem mỗi dòng làm gì
Nhiệm vụ trong chương trình này chỉ là một hàm chấp nhận một chuỗi và một hàng đợi làm tham số. Khi được thực thi, nó sẽ tìm mọi thứ trong hàng đợi để xử lý. Nếu có việc phải làm, thì nó sẽ lấy các giá trị ra khỏi hàng đợi, bắt đầu vòng lặp 01 để đếm đến giá trị đó và xuất ra tổng số ở cuối. Nó tiếp tục hoàn thành công việc khỏi hàng đợi cho đến khi không còn gì và nó thoátKhi chương trình này được chạy, nó sẽ tạo ra kết quả như bạn thấy bên dưới
Điều này cho thấy rằng 02 làm tất cả công việc. Vòng lặp 03 mà 02 truy cập trong vòng 5 tiêu thụ tất cả công việc trên hàng đợi và xử lý nó. Khi vòng lặp đó thoát ra, 06 sẽ có cơ hội chạy. Tuy nhiên, nó thấy rằng hàng đợi trống, vì vậy 06 in ra một câu lệnh nói rằng nó không có gì để làm và sau đó thoát ra. Không có gì trong mã cho phép cả 02 và 06 chuyển ngữ cảnh và làm việc cùng nhauĐồng thời hợp tác đơn giảnPhiên bản tiếp theo của chương trình cho phép hai tác vụ hoạt động cùng nhau. Thêm câu lệnh 00 có nghĩa là vòng lặp sẽ mang lại quyền kiểm soát tại điểm đã chỉ định trong khi vẫn duy trì ngữ cảnh của nó. Bằng cách này, tác vụ tạo năng suất có thể được khởi động lại sauCâu lệnh 00 biến 5 thành một trình tạo. Hàm tạo được gọi giống như bất kỳ hàm nào khác trong Python, nhưng khi câu lệnh 00 được thực thi, quyền điều khiển được trả về cho người gọi hàm. Đây thực chất là một công tắc ngữ cảnh, khi điều khiển chuyển từ chức năng trình tạo sang trình gọiPhần thú vị là quyền điều khiển có thể được trả lại cho hàm tạo bằng cách gọi 04 trên trình tạo. Đây là một chuyển đổi ngữ cảnh trở lại hàm tạo, giúp chọn thực thi với tất cả các biến hàm đã được xác định trước khi 00 vẫn còn nguyên vẹnVòng lặp 03 trong 7 tận dụng lợi thế này khi nó gọi 08. Câu lệnh này khởi động lại tác vụ tại điểm mà nó đã tạo ra trước đó. Tất cả điều này có nghĩa là bạn đang kiểm soát khi chuyển ngữ cảnh xảy ra. khi câu lệnh 00 được thực thi trong 5Đây là một hình thức hợp tác đa nhiệm. Chương trình đang mang lại quyền kiểm soát bối cảnh hiện tại của nó để thứ khác có thể chạy. Trong trường hợp này, nó cho phép vòng lặp 03 trong 7 chạy hai phiên bản của 5 dưới dạng hàm tạo. Mỗi phiên bản sử dụng công việc từ cùng một hàng đợi. Đây là một loại thông minh, nhưng cũng cần rất nhiều công việc để có được kết quả như chương trình đầu tiên. Chương trình 44 minh họa đồng thời đơn giản này và được liệt kê bên dưới 0Đây là những gì đang xảy ra trong đoạn mã trên
Đây là đầu ra được tạo ra khi bạn chạy chương trình này 0Bạn có thể thấy rằng cả 02 và 06 đều đang chạy và sử dụng công việc từ hàng đợi. Đây là mục đích, vì cả hai tác vụ đều đang xử lý công việc và mỗi tác vụ chịu trách nhiệm cho hai mục trong hàng đợi. Điều này thật thú vị, nhưng một lần nữa, phải mất khá nhiều công sức để đạt được những kết quả nàyMẹo ở đây là sử dụng câu lệnh 00, biến 5 thành bộ tạo và thực hiện chuyển đổi ngữ cảnh. Chương trình sử dụng công tắc ngữ cảnh này để trao quyền điều khiển cho vòng lặp 03 trong 7, cho phép hai phiên bản của một tác vụ cùng chạyLưu ý cách 06 xuất tổng đầu tiên. Điều này có thể khiến bạn nghĩ rằng các tác vụ đang chạy không đồng bộ. Tuy nhiên, đây vẫn là chương trình đồng bộ. Nó được cấu trúc để hai tác vụ có thể trao đổi ngữ cảnh qua lại. Lý do tại sao 06 đưa ra tổng số đầu tiên là vì nó chỉ đếm đến 10, trong khi 02 đang đếm đến 15. 06 chỉ cần đạt đến tổng số đầu tiên, do đó, nó sẽ in đầu ra của nó ra bàn điều khiển trước 02Ghi chú. Tất cả các mã ví dụ tiếp theo từ thời điểm này đều sử dụng một mô-đun có tên là codetiming theo thời gian và xuất ra các đoạn mã mất bao lâu để thực thi. Có một bài viết tuyệt vời ở đây về RealPython đi sâu về mô-đun codetiming và cách sử dụng nó Mô-đun này là một phần của Chỉ mục gói Python và được xây dựng bởi Geir Arne Hjelle, thành viên của nhóm Real Python. Geir Arne đã giúp tôi rất nhiều trong việc xem xét và gợi ý những điều cho bài viết này. Nếu bạn đang viết mã cần bao gồm chức năng định thời gian, thì mô-đun định thời gian của Geir Arne rất đáng xem Để cung cấp mô-đun lập mã thời gian cho các ví dụ tiếp theo, bạn cần cài đặt mô-đun này. Điều này có thể được thực hiện với 31 bằng lệnh này. 32, hoặc với lệnh này. 33. Tệp 2 là một phần của kho mã ví dụLoại bỏ các quảng cáoĐồng thời hợp tác với các cuộc gọi chặnPhiên bản tiếp theo của chương trình giống như phiên bản trước, ngoại trừ việc bổ sung một 35 trong phần thân của vòng lặp nhiệm vụ của bạn. Điều này thêm độ trễ dựa trên giá trị được lấy từ hàng đợi công việc cho mỗi lần lặp lại của vòng lặp tác vụ. Độ trễ mô phỏng tác động của cuộc gọi chặn xảy ra trong tác vụ của bạnCuộc gọi chặn là mã ngăn CPU làm bất cứ điều gì khác trong một khoảng thời gian. Trong các thử nghiệm tưởng tượng ở trên, nếu cha mẹ không thể thoát khỏi việc cân bằng sổ séc cho đến khi hoàn tất, thì đó sẽ là một cuộc gọi chặn 35 làm điều tương tự trong ví dụ này, bởi vì CPU không thể làm gì khác ngoài việc đợi hết thời gian trì hoãn 4Đây là điểm khác biệt trong đoạn mã trên
Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau 8Như trước đây, cả 02 và 06 đều đang chạy, tiêu thụ công việc từ hàng đợi và xử lý nó. Tuy nhiên, ngay cả khi bổ sung độ trễ, bạn có thể thấy rằng đồng thời hợp tác không mang lại cho bạn bất cứ điều gì. Độ trễ dừng quá trình xử lý của toàn bộ chương trình và CPU chỉ đợi độ trễ IO kết thúcĐây chính xác là ý nghĩa của việc chặn mã trong tài liệu Python async. Bạn sẽ nhận thấy rằng thời gian cần thiết để chạy toàn bộ chương trình chỉ là thời gian tích lũy của tất cả các lần trì hoãn. Chạy các nhiệm vụ theo cách này không phải là một chiến thắng Đồng thời hợp tác với các cuộc gọi không chặnPhiên bản tiếp theo của chương trình đã được sửa đổi khá nhiều. Nó sử dụng các tính năng không đồng bộ của Python bằng cách sử dụng asyncio/await được cung cấp trong Python 3 Các mô-đun 37 và 4 đã được thay thế bằng gói 84. Điều này cho phép chương trình của bạn truy cập vào chức năng xếp hàng và ngủ thân thiện (không chặn) không đồng bộ. Thay đổi thành 5 xác định nó là không đồng bộ với việc bổ sung tiền tố 86 trên dòng 4. Điều này cho Python biết rằng hàm sẽ không đồng bộMột thay đổi lớn khác là loại bỏ các câu lệnh 35 và 00 và thay thế chúng bằng 89. Điều này tạo ra độ trễ không chặn sẽ thực hiện chuyển đổi ngữ cảnh trở lại người gọi 7Vòng lặp 03 bên trong 7 không còn tồn tại. Thay vì 03, có một cuộc gọi đến 04. Điều này nói với 84 hai điều
Dòng cuối cùng của chương trình 07 chạy 7. Điều này tạo ra cái được gọi là vòng lặp sự kiện). Vòng lặp này sẽ chạy 7, đến lượt nó sẽ chạy hai phiên bản của 5Vòng lặp sự kiện là trung tâm của hệ thống không đồng bộ Python. Nó chạy tất cả mã, bao gồm cả 7. Khi mã tác vụ đang thực thi, CPU đang bận làm việc. Khi đạt đến, một chuyển đổi ngữ cảnh xảy ra và điều khiển quay trở lại vòng lặp sự kiện. Vòng lặp sự kiện xem xét tất cả các tác vụ đang chờ một sự kiện (trong trường hợp này là thời gian chờ của 13) và chuyển quyền kiểm soát cho một tác vụ có sự kiện đã sẵn sàng 89 không bị chặn đối với CPU. Thay vì đợi hết thời gian trễ, CPU đăng ký một sự kiện ngủ trên hàng đợi tác vụ của vòng lặp sự kiện và thực hiện chuyển ngữ cảnh bằng cách chuyển điều khiển tới vòng lặp sự kiện. Vòng lặp sự kiện liên tục tìm kiếm các sự kiện đã hoàn thành và chuyển điều khiển trở lại tác vụ đang chờ sự kiện đó. Bằng cách này, CPU có thể luôn bận nếu có công việc, trong khi vòng lặp sự kiện giám sát các sự kiện sẽ xảy ra trong tương laiGhi chú. Một chương trình không đồng bộ chạy trong một luồng thực thi. Việc chuyển ngữ cảnh từ phần mã này sang phần mã khác sẽ ảnh hưởng đến dữ liệu hoàn toàn nằm trong tầm kiểm soát của bạn. Điều này có nghĩa là bạn có thể nguyên tử hóa và hoàn thành tất cả quyền truy cập dữ liệu bộ nhớ dùng chung trước khi thực hiện chuyển ngữ cảnh. Điều này đơn giản hóa vấn đề bộ nhớ dùng chung vốn có trong mã luồng Mã 15 được liệt kê bên dưới 09Đây là điểm khác biệt giữa chương trình này và 16
Khi bạn nhìn vào đầu ra của chương trình này, hãy chú ý cách cả 02 và 06 bắt đầu cùng một lúc, sau đó đợi lệnh gọi IO giả 3Điều này chỉ ra rằng 89 không bị chặn và công việc khác đang được thực hiệnKhi kết thúc chương trình, bạn sẽ nhận thấy tổng thời gian đã trôi qua về cơ bản chỉ bằng một nửa thời gian để 16 chạy. Đó là lợi thế của một chương trình sử dụng các tính năng không đồng bộ của Python. Mỗi tác vụ có thể chạy 89 cùng một lúc. Tổng thời gian thực hiện của chương trình bây giờ ít hơn tổng thời gian của các phần của nó. Bạn đã thoát khỏi mô hình đồng bộLoại bỏ các quảng cáoCác cuộc gọi HTTP đồng bộ (Chặn)Phiên bản tiếp theo của chương trình là một bước tiến cũng như một bước lùi. Chương trình đang thực hiện một số công việc thực tế với IO thực bằng cách thực hiện các yêu cầu HTTP tới danh sách URL và nhận nội dung trang. Tuy nhiên, nó hoạt động theo cách chặn (đồng bộ) Chương trình đã được sửa đổi để nhập mô-đun 39 tuyệt vời để thực hiện các yêu cầu HTTP thực tế. Ngoài ra, hàng đợi hiện chứa danh sách URL, thay vì số. Ngoài ra, 5 không còn tăng bộ đếm. Thay vào đó, 39 lấy nội dung của một URL được truy xuất từ hàng đợi và in thời gian cần thiết để làm như vậyMã 42 được liệt kê dưới đây 3Đây là những gì đang xảy ra trong chương trình này
Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau 8Giống như trong các phiên bản trước của chương trình, 00 biến 5 thành máy phát điện. Nó cũng thực hiện chuyển đổi ngữ cảnh cho phép thực hiện nhiệm vụ khácMỗi tác vụ nhận một URL từ hàng đợi công việc, truy xuất nội dung của trang và báo cáo mất bao lâu để nhận được nội dung đó Như trước đây, 00 cho phép cả hai tác vụ của bạn cùng chạy. Tuy nhiên, vì chương trình này đang chạy đồng bộ, mỗi lệnh gọi 58 sẽ chặn CPU cho đến khi trang được truy xuất. Lưu ý tổng thời gian cần thiết để chạy toàn bộ chương trình khi kết thúc. Điều này sẽ có ý nghĩa cho ví dụ tiếp theoCuộc gọi HTTP không đồng bộ (Không chặn)Phiên bản này của chương trình sửa đổi phiên bản trước đó để sử dụng các tính năng không đồng bộ của Python. Nó cũng nhập mô-đun 59, là thư viện để thực hiện các yêu cầu HTTP theo kiểu không đồng bộ bằng cách sử dụng 84Các tác vụ ở đây đã được sửa đổi để loại bỏ lệnh gọi 00 vì mã để thực hiện lệnh gọi HTTP 62 không còn bị chặn nữa. Nó cũng thực hiện chuyển đổi ngữ cảnh trở lại vòng lặp sự kiệnChương trình 63 được liệt kê bên dưới 0Đây là những gì đang xảy ra trong chương trình này
Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau 1Hãy xem tổng thời gian đã trôi qua, cũng như thời gian riêng lẻ để nhận nội dung của từng URL. Bạn sẽ thấy rằng thời lượng bằng khoảng một nửa thời gian tích lũy của tất cả các lệnh gọi HTTP 62. Điều này là do các lệnh gọi HTTP 62 đang chạy không đồng bộ. Nói cách khác, bạn đang tận dụng lợi thế của CPU một cách hiệu quả hơn bằng cách cho phép nó thực hiện nhiều yêu cầu cùng một lúcVì CPU quá nhanh nên ví dụ này có thể tạo nhiều tác vụ bằng số lượng URL. Trong trường hợp này, thời gian chạy của chương trình sẽ là thời gian truy xuất URL chậm nhất Loại bỏ các quảng cáoSự kết luậnBài viết này đã cung cấp cho bạn các công cụ cần thiết để bắt đầu biến các kỹ thuật lập trình không đồng bộ thành một phần trong tiết mục của bạn. Sử dụng các tính năng không đồng bộ của Python cho phép bạn kiểm soát theo chương trình khi diễn ra chuyển ngữ cảnh. Điều này có nghĩa là nhiều vấn đề khó khăn hơn mà bạn có thể thấy trong lập trình luồng sẽ dễ giải quyết hơn Lập trình không đồng bộ là một công cụ mạnh mẽ, nhưng nó không hữu ích cho mọi loại chương trình. Ví dụ, nếu bạn đang viết một chương trình tính số pi đến chữ số thập phân thứ một triệu, thì mã không đồng bộ sẽ không giúp ích gì cho bạn. Loại chương trình đó bị ràng buộc bởi CPU, không có nhiều IO. Tuy nhiên, nếu bạn đang cố gắng triển khai máy chủ hoặc chương trình thực hiện IO (như truy cập tệp hoặc mạng), thì việc sử dụng các tính năng không đồng bộ của Python có thể tạo ra sự khác biệt lớn Tóm lại, bạn đã học được
Bạn có thể lấy mã cho tất cả các chương trình ví dụ được sử dụng trong hướng dẫn này Tải xuống mã. Nhấp vào đây để tải xuống mã mà bạn sẽ sử dụng để tìm hiểu về các tính năng không đồng bộ trong Python trong hướng dẫn này Bây giờ bạn đã được trang bị những kỹ năng mạnh mẽ này, bạn có thể đưa chương trình của mình lên một tầm cao mới Đánh dấu là đã hoàn thành 🐍 Thủ thuật Python 💌 Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python Gửi cho tôi thủ thuật Python » Giới thiệu về Doug Farrell Doug là nhà phát triển Python với hơn 25 năm kinh nghiệm. Anh ấy viết về Python trên trang web cá nhân của mình và làm việc với tư cách là Kỹ sư web cấp cao của Shutterfly » Thông tin thêm về DougMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là Aldren Brad Geir Arne Jaya Joanna Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bậc thầy Kỹ năng Python trong thế giới thực Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng các chuyên gia Pythonistas Nâng cao kỹ năng Python của bạn » Bạn nghĩ sao? Đánh giá bài viết này Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì? Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi Chúng ta có thể gọi phương thức async trong phương thức đồng bộ không?Sử dụng thuộc tính Kết quả trên Tác vụ không đồng bộ , như vậy. // Phương thức đồng bộ. Phương thức void()
Không đồng bộ có nhanh hơn đồng bộ hóa Python không?Async không bị chặn, có nghĩa là nó sẽ gửi nhiều yêu cầu đến một máy chủ. Đồng bộ hóa đang chặn — nó sẽ chỉ gửi cho máy chủ một yêu cầu tại một thời điểm và sẽ đợi máy chủ trả lời yêu cầu đó. Async tăng thông lượng vì có thể chạy nhiều thao tác cùng lúc .
Python không đồng bộ hay đồng bộ?Có hai loại phương thức cơ bản trong Parallels Python API. đồng bộ và không đồng bộ . Khi một phương thức đồng bộ được gọi, nó sẽ hoàn thành việc thực thi trước khi quay lại trình gọi. Một phương thức không đồng bộ bắt đầu một công việc ở chế độ nền và trả lại cho người gọi ngay lập tức.
Điều gì xảy ra khi bạn gọi một chức năng không đồng bộ?Các hàm không đồng bộ sẽ luôn trả về một giá trị . Nó đảm bảo rằng một lời hứa được trả lại và nếu nó không được trả lại thì JavaScript sẽ tự động gói nó trong một lời hứa được giải quyết bằng giá trị của nó. |