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

Trong bài viết này, bạn sẽ học

  • chương trình đồng bộ là gì
  • Chương trình không đồng bộ là gì
  • Tại sao bạn có thể muốn viết một chương trình không đồng bộ
  • Cách sử dụng các tính năng không đồng bộ của Python

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

  • Các chương trình xử lý hàng loạt thường được tạo dưới dạng các chương trình đồng bộ. Bạn nhận được một số đầu vào, xử lý nó và tạo ra một số đầu ra. Các bước thực hiện lần lượt cho đến khi chương trình đạt được đầu ra mong muốn. Chương trình chỉ cần chú ý đến các bước và thứ tự của chúng

  • Các chương trình dòng lệnh là các quy trình nhỏ, nhanh chạy trong thiết bị đầu cuối. Các tập lệnh này được sử dụng để tạo một thứ gì đó, chuyển đổi thứ này thành thứ khác, tạo báo cáo hoặc có thể liệt kê một số dữ liệu. Điều này có thể được thể hiện dưới dạng một loạt các bước của chương trình được thực hiện tuần tự cho đến khi hoàn thành chương trình

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áo

Xâ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ình

Khi 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ó

  • Cân đối sổ séc là nhiệm vụ đồng bộ. Bước này nối tiếp bước kia cho đến khi hoàn thành. Bạn đang tự mình làm tất cả công việc

  • Tuy nhiên, bạn có thể thoát khỏi sổ séc để giặt đồ. Bạn lấy quần áo ra khỏi máy sấy, di chuyển quần áo từ máy giặt sang máy sấy và bắt đầu một mẻ giặt khác trong máy giặt

  • Làm việc với máy giặt và máy sấy là một nhiệm vụ đồng bộ, nhưng phần lớn công việc diễn ra sau khi máy giặt và máy sấy được khởi động. Khi bạn đã hoàn thành chúng, bạn có thể bỏ đi và quay lại nhiệm vụ sổ séc. Tại thời điểm này, các nhiệm vụ của máy giặt và máy sấy đã trở nên không đồng bộ. Máy giặt và máy sấy sẽ chạy độc lập cho đến khi còi kêu [thông báo cho bạn biết rằng công việc cần chú ý]

  • Theo dõi con bạn là một nhiệm vụ không đồng bộ khác. Khi chúng được thiết lập và chơi, phần lớn chúng có thể làm như vậy một cách độc lập. Điều này thay đổi khi ai đó cần được chú ý, chẳng hạn như khi ai đó bị đói hoặc bị thương. Khi một trong những đứa trẻ của bạn hét lên báo động, bạn phản ứng. Những đứa trẻ là một nhiệm vụ lâu dài với mức độ ưu tiên cao. Xem chúng thay thế bất kỳ nhiệm vụ nào khác mà bạn có thể đang làm, chẳng hạn như sổ séc hoặc giặt ủi

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ài

Nế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áo

Thử nghiệm suy nghĩ #2. Cha mẹ thăm dò ý kiến

Nế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 đề

  1. Phụ huynh có thể dành nhiều thời gian để kiểm tra những thứ không cần chú ý. Máy giặt và máy sấy chưa xong, và bọn trẻ không cần quan tâm trừ khi có điều gì đó bất ngờ xảy ra

  2. Phụ huynh có thể bỏ lỡ các nhiệm vụ đã hoàn thành cần chú ý. Chẳng hạn, nếu máy giặt hoàn thành chu kỳ của nó khi bắt đầu khoảng thời gian bỏ phiếu, thì nó sẽ không nhận được bất kỳ sự chú ý nào trong tối đa mười lăm phút. Hơn nữa, trông chừng bọn trẻ được cho là nhiệm vụ ưu tiên cao nhất. Họ không thể chịu đựng được mười lăm phút mà không chú ý khi có điều gì đó có thể sai nghiêm trọng.

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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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áo

Lậ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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
3 trong kho lưu trữ được liệt kê đầy đủ bên dưới

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]

Hãy xem mỗi dòng làm gì

  • Dòng 1 nhập mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    4. Đây là nơi chương trình lưu trữ công việc cần thực hiện bởi các tác vụ
  • Dòng 3 đến 13 định nghĩa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5. Hàm này lấy công việc ra khỏi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6 và xử lý công việc cho đến khi không còn việc gì để làm
  • Dòng 15 định nghĩa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    7 để chạy các tác vụ của chương trình
  • Dòng 20 tạo
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6. Tất cả các tác vụ sử dụng tài nguyên được chia sẻ này để truy xuất công việc
  • Dòng 23 đến 24 đưa công việc vào
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6. Trong trường hợp này, đó chỉ là một số giá trị ngẫu nhiên cho các tác vụ xử lý
  • Dòng 27 tạo danh sách các bộ nhiệm vụ, với các giá trị tham số, các nhiệm vụ đó sẽ được chuyển
  • Các dòng 30 đến 31 lặp qua danh sách các bộ nhiệm vụ, gọi từng bộ và chuyển các giá trị tham số đã xác định trước đó
  • Dòng 34 gọi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    7 để chạy chương trình

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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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át

Khi 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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do

Điều này cho thấy rằng

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 làm tất cả công việc. Vòng lặp
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03 mà
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 truy cập trong vòng
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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,
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
06 sẽ có cơ hội chạy. Tuy nhiên, nó thấy rằng hàng đợi trống, vì vậy
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ả
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 và
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
06 chuyển ngữ cảnh và làm việc cùng nhau

Đồng thời hợp tác đơn giản

Phiê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

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
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 sau

Câu lệnh

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 biến
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
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ọi

Phầ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

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
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
 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 vẫn còn nguyên vẹn

Vòng lặp

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03 trong
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7 tận dụng lợi thế này khi nó gọi
 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
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
 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 được thực thi trong
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03 trong
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7 chạy hai phiên bản của
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
44 minh họa đồng thời đơn giản này và được liệt kê bên dưới

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
0

Đây là những gì đang xảy ra trong đoạn mã trên

  • Các dòng 3 đến 11 định nghĩa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 như trước, nhưng việc thêm
     1import queue
     2
     3def task[name, work_queue]:
     4    if work_queue.empty[]:
     5        print[f"Task {name} nothing to do"]
     6    else:
     7        while not work_queue.empty[]:
     8            count = work_queue.get[]
     9            total = 0
    10            print[f"Task {name} running"]
    11            for x in range[count]:
    12                total += 1
    13            print[f"Task {name} total: {total}"]
    14
    15def main[]:
    16    """
    17    This is the main entry point for the program
    18    """
    19    # Create the queue of work
    20    work_queue = queue.Queue[]
    21
    22    # Put some work in the queue
    23    for work in [15, 10, 5, 2]:
    24        work_queue.put[work]
    25
    26    # Create some synchronous tasks
    27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
    28
    29    # Run the tasks
    30    for t, n, q in tasks:
    31        t[n, q]
    32
    33if __name__ == "__main__":
    34    main[]
    
    00 vào Dòng 10 biến hàm thành một trình tạo. Đây là nơi thực hiện chuyển đổi ngữ cảnh và điều khiển được trao lại cho vòng lặp
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    03 trong
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    7
  • Dòng 25 tạo danh sách nhiệm vụ, nhưng theo cách hơi khác so với cách bạn thấy trong mã ví dụ trước. Trong trường hợp này, mỗi tác vụ được gọi với các tham số của nó như được nhập vào biến danh sách
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    49. Điều này là cần thiết để chức năng tạo
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 chạy lần đầu tiên
  • Các dòng 31 đến 36 là các sửa đổi đối với vòng lặp
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    03 trong
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    7 cho phép
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 chạy hợp tác. Đây là nơi điều khiển quay trở lại từng phiên bản của
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 khi nó mang lại kết quả, cho phép vòng lặp tiếp tục và chạy một tác vụ khác
  • Dòng 32 trả lại quyền điều khiển cho
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 và tiếp tục thực hiện sau thời điểm mà
     1import queue
     2
     3def task[name, work_queue]:
     4    if work_queue.empty[]:
     5        print[f"Task {name} nothing to do"]
     6    else:
     7        while not work_queue.empty[]:
     8            count = work_queue.get[]
     9            total = 0
    10            print[f"Task {name} running"]
    11            for x in range[count]:
    12                total += 1
    13            print[f"Task {name} total: {total}"]
    14
    15def main[]:
    16    """
    17    This is the main entry point for the program
    18    """
    19    # Create the queue of work
    20    work_queue = queue.Queue[]
    21
    22    # Put some work in the queue
    23    for work in [15, 10, 5, 2]:
    24        work_queue.put[work]
    25
    26    # Create some synchronous tasks
    27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
    28
    29    # Run the tasks
    30    for t, n, q in tasks:
    31        t[n, q]
    32
    33if __name__ == "__main__":
    34    main[]
    
    00 được gọi
  • Dòng 36 đặt biến
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    87. Vòng lặp
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    03 kết thúc khi tất cả các tác vụ đã được hoàn thành và xóa khỏi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    49

Đây là đầu ra được tạo ra khi bạn chạy chương trình này

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
0

Bạn có thể thấy rằng cả

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 và
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ày

Mẹo ở đây là sử dụng câu lệnh

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00, biến
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03 trong
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7, cho phép hai phiên bản của một tác vụ cùng chạy

Lưu ý cách

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
06 đưa ra tổng số đầu tiên là vì nó chỉ đếm đến 10, trong khi
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 đang đếm đến 15.
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02

Ghi 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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
31 bằng lệnh này.
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
32, hoặc với lệnh này.
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
33. Tệp
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ặn

Phiê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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ạn

Cuộ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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
4

Đây là điểm khác biệt trong đoạn mã trên

  • Dòng 1 nhập mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    37 để cấp cho chương trình quyền truy cập vào
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    38
  • Dòng 3 nhập mã
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 từ mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    30
  • Dòng 6 tạo phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 được sử dụng để đo thời gian thực hiện cho mỗi lần lặp của vòng lặp tác vụ
  • Dòng 10 bắt đầu phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32
  • Dòng 11 thay đổi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 để bao gồm một
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    35 để bắt chước độ trễ IO. Điều này thay thế vòng lặp
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    01 đã đếm trong
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    3
  • Dòng 12 dừng phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32 và xuất thời gian đã trôi qua kể từ khi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    38 được gọi
  • Dòng 30 tạo một trình quản lý bối cảnh
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 sẽ xuất ra thời gian đã trôi qua mà toàn bộ vòng lặp while đã thực hiện

Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
8

Như trước đây, cả

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 và
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ặn

Phiê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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
37 và
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
4 đã được thay thế bằng gói
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
5 xác định nó là không đồng bộ với việc bổ sung tiền tố
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
35 và
 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 và thay thế chúng bằng
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7

Vòng lặp

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03 bên trong
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7 không còn tồn tại. Thay vì
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
03, có một cuộc gọi đến
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
04. Điều này nói với
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
84 hai điều

  1. Tạo hai tác vụ dựa trên
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 và bắt đầu chạy chúng
  2. Chờ cho cả hai điều này được hoàn thành trước khi di chuyển về phía trước

Dòng cuối cùng của chương trình

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
07 chạy
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
7, đến lượt nó sẽ chạy hai phiên bản của
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
5

Vò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ả

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
13] và chuyển quyền kiểm soát cho một tác vụ có sự kiện đã sẵn sàng

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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 lai

Ghi 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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
15 được liệt kê bên dưới

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
09

Đây là điểm khác biệt giữa chương trình này và

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
16

  • Dòng 1 nhập
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    84 để có quyền truy cập vào chức năng không đồng bộ của Python. Điều này thay thế việc nhập khẩu
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    37
  • Dòng 2 nhập mã
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 từ mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    30
  • Dòng 4 hiển thị thêm từ khóa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    86 trước định nghĩa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5. Điều này thông báo cho chương trình rằng
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    23 có thể chạy không đồng bộ
  • Dòng 5 tạo phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 được sử dụng để đo thời gian thực hiện cho mỗi lần lặp của vòng lặp nhiệm vụ
  • Dòng 9 bắt đầu phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32
  • Dòng 10 thay thế
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    35 bằng không chặn
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    13, điều này cũng mang lại quyền kiểm soát [hoặc chuyển ngữ cảnh] trở lại vòng lặp sự kiện chính
  • Dòng 11 dừng phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32 và xuất thời gian đã trôi qua kể từ khi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    38 được gọi
  • Dòng 18 tạo
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6 không đồng bộ không chặn
  • Dòng 21 đến 22 đưa công việc vào
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6 theo cách không đồng bộ bằng cách sử dụng từ khóa
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    12
  • Dòng 25 tạo một trình quản lý ngữ cảnh
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 sẽ xuất ra thời gian đã trôi qua mà toàn bộ vòng lặp while đã thực hiện
  • Dòng 26 đến 29 tạo 2 tác vụ và gộp chúng lại với nhau, vì vậy chương trình sẽ đợi cả 2 tác vụ hoàn thành
  • Dòng 32 bắt đầu chương trình chạy không đồng bộ. Nó cũng bắt đầu vòng lặp sự kiện nội bộ

Khi bạn nhìn vào đầu ra của chương trình này, hãy chú ý cách cả

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
02 và
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
06 bắt đầu cùng một lúc, sau đó đợi lệnh gọi IO giả

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
3

Điều này chỉ ra rằng

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
89 không bị chặn và công việc khác đang được thực hiện

Khi 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 để

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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áo

Cá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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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,
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
5 không còn tăng bộ đếm. Thay vào đó,
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ậy

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
42 được liệt kê dưới đây

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
3

Đây là những gì đang xảy ra trong chương trình này

  • Dòng 2 nhập
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39, cung cấp một cách thuận tiện để thực hiện cuộc gọi HTTP
  • Dòng 3 nhập mã
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 từ mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    30
  • Dòng 6 tạo phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 được sử dụng để đo thời gian thực hiện cho mỗi lần lặp của vòng lặp tác vụ
  • Dòng 11 bắt đầu phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32
  • Dòng 12 giới thiệu độ trễ, tương tự như
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    16. Tuy nhiên, lần này nó gọi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    49, trả về nội dung của URL được lấy từ
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6
  • Dòng 13 dừng phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32 và xuất thời gian đã trôi qua kể từ khi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    38 được gọi
  • Dòng 23 đến 32 đưa danh sách các URL vào
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6
  • Dòng 39 tạo một trình quản lý bối cảnh
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 sẽ xuất ra thời gian đã trôi qua mà toàn bộ vòng lặp while đã thực hiện

Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
8

Giống như trong các phiên bản trước của chương trình,

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 biến
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ác

Mỗ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,

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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 theo

Cuộ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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
84

Các tác vụ ở đây đã được sửa đổi để loại bỏ lệnh gọi

 1import queue
 2
 3def task[name, work_queue]:
 4    if work_queue.empty[]:
 5        print[f"Task {name} nothing to do"]
 6    else:
 7        while not work_queue.empty[]:
 8            count = work_queue.get[]
 9            total = 0
10            print[f"Task {name} running"]
11            for x in range[count]:
12                total += 1
13            print[f"Task {name} total: {total}"]
14
15def main[]:
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue[]
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put[work]
25
26    # Create some synchronous tasks
27    tasks = [[task, "One", work_queue], [task, "Two", work_queue]]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t[n, q]
32
33if __name__ == "__main__":
34    main[]
00 vì mã để thực hiện lệnh gọi HTTP
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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ện

Chương trình

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
63 được liệt kê bên dưới

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
0

Đây là những gì đang xảy ra trong chương trình này

  • Dòng 2 nhập thư viện
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    59, cung cấp cách thức không đồng bộ để thực hiện cuộc gọi HTTP
  • Dòng 3 nhập mã
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 từ mô-đun
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    30
  • Dòng 5 đánh dấu
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    5 là một hàm không đồng bộ
  • Dòng 6 tạo phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 được sử dụng để đo thời gian thực hiện cho mỗi lần lặp của vòng lặp tác vụ
  • Dòng 7 tạo trình quản lý ngữ cảnh phiên
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    59
  • Dòng 8 tạo trình quản lý ngữ cảnh phản hồi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    59. Nó cũng thực hiện một cuộc gọi HTTP
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    62 tới URL được lấy từ
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    6
  • Dòng 11 bắt đầu phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32
  • Dòng 12 sử dụng phiên để lấy văn bản từ URL không đồng bộ
  • Dòng 13 dừng phiên bản
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    32 và xuất thời gian đã trôi qua kể từ khi
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    38 được gọi
  • Dòng 39 tạo một trình quản lý bối cảnh
    Task One running
    Task One total: 15
    Task One running
    Task One total: 10
    Task One running
    Task One total: 5
    Task One running
    Task One total: 2
    Task Two nothing to do
    
    39 sẽ xuất ra thời gian đã trôi qua mà toàn bộ vòng lặp while đã thực hiện

Khi bạn chạy chương trình này, bạn sẽ thấy đầu ra sau

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
1

Hã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

Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
62. Điều này là do các lệnh gọi HTTP
Task One running
Task One total: 15
Task One running
Task One total: 10
Task One running
Task One total: 5
Task One running
Task One total: 2
Task Two nothing to do
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úc

Vì 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áo

Sự kết luận

Bà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

  • Các chương trình đồng bộ là gì
  • Các chương trình không đồng bộ khác nhau như thế nào, nhưng cũng mạnh mẽ và dễ quản lý
  • Tại sao bạn có thể muốn viết các chương trình không đồng bộ
  • Cách sử dụng các tính năng không đồng bộ tích hợp trong Python

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ề Doug

Mỗ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
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 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ẻ Email

Bà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ó.

Chủ Đề