Trong Phòng của Nhà văn tuần này - một loạt blog thường xuyên gồm các bài báo và hướng dẫn được viết bởi các nhà công nghệ trong Cộng đồng Andela của chúng tôi - Ezzeddin Abdullah giới thiệu về lập trình không đồng bộ trong Python bằng Async IO
Viết mã tuần tự [hoặc đồng bộ] quen thuộc với nhiều lập trình viên, ngay cả khi họ mới bắt đầu. Đó là loại mã được thực thi từng dòng một, từng lệnh một
Trong thế giới không đồng bộ, sự xuất hiện của các sự kiện độc lập với luồng chương trình chính. Điều này có nghĩa là các hành động được thực thi trong nền mà không cần chờ hoàn thành hành động trước đó
Nói cách khác, các dòng mã được thực hiện đồng thời
Hãy tưởng tượng bạn có một số nhiệm vụ độc lập nhất định và mỗi nhiệm vụ mất rất nhiều thời gian để hoàn thành. Đầu ra của chúng không phụ thuộc vào nhau. Vì vậy, bạn muốn bắt đầu tất cả chúng cùng một lúc. Nếu các tác vụ này được thực hiện theo một thứ tự cụ thể, chương trình sẽ phải đợi mỗi tác vụ hoàn thành trước khi bắt đầu tác vụ tiếp theo. Thời gian chờ đợi này đang chặn chương trình
Mô hình lập trình không đồng bộ giúp thực hiện đồng thời các tác vụ này và đảm bảo bạn có thể đánh bại thời gian chờ đợi đó và sử dụng tài nguyên hiệu quả hơn
Python 3 có hỗ trợ riêng cho lập trình không đồng bộ, Async IO, cung cấp một cách đơn giản để thực thi các tác vụ đồng thời
Đầu tiên, hãy thiết lập môi trường của chúng ta và bắt đầu
Thiết lập môi trường
Trong hướng dẫn này, chúng tôi sẽ sử dụng mô-đun async io trong Python 3. 7 trở lên, vì vậy chúng ta cần tạo một Python 3 mới. 7 môi trường. Một cách Python rõ ràng là thiết lập một môi trường ảo với conda và sau đó kích hoạt nó bằng các lệnh sau
Khối xây dựng lập trình không đồng bộ
Có 3 khối xây dựng chính của lập trình không đồng bộ Python
- Nhiệm vụ chính là vòng lặp sự kiện, chịu trách nhiệm quản lý các tác vụ không đồng bộ và phân phối chúng để thực thi
- Coroutines là các chức năng lên lịch thực hiện các sự kiện
- Hợp đồng tương lai là kết quả của việc thực hiện coroutine. Kết quả này có thể là một ngoại lệ
Giới thiệu async trong Python
Hai thành phần chính được giới thiệu trong Python
async io
là gói Python cho phép API chạy và quản lý coroutineasync/await
để giúp bạn xác định coroutines
Chức năng và hành vi của mã sẽ khác khi bạn chọn không đồng bộ hoặc đồng bộ hóa để thiết kế mã của mình
Nói rõ hơn, để thực hiện cuộc gọi HTTP, hãy cân nhắc sử dụng aiohttp
, đây là gói Python cho phép bạn thực hiện cuộc gọi HTTP không đồng bộ. Nó có thể là một công cụ cần thiết nếu bạn bị chặn vì thư viện requests
Tương tự, nếu bạn đang làm việc với trình điều khiển Mongo, thay vì dựa vào trình điều khiển đồng bộ như mongo-python
, bạn phải sử dụng trình điều khiển không đồng bộ như moto
để truy cập MongoDB không đồng bộ
Trong thế giới không đồng bộ, mọi thứ chạy trong một vòng lặp sự kiện. Điều này cho phép bạn chạy một số coroutine cùng một lúc. Chúng ta sẽ xem coroutine là gì trong hướng dẫn này
Mọi thứ bên trong async def
là mã không đồng bộ và mọi thứ khác là đồng bộ
Viết mã không đồng bộ không dễ như viết mã đồng bộ. Mô hình không đồng bộ Python dựa trên các khái niệm như sự kiện, gọi lại, vận chuyển, giao thức và tương lai
Mọi thứ diễn ra nhanh chóng trong thế giới không đồng bộ của Python, vì vậy hãy theo dõi các bản cập nhật mới nhất
Cách thức hoạt động của asyncio
Gói asyncio
cung cấp hai khóa, async
và await
Hãy xem ví dụ về thế giới xin chào async
này
Thoạt nhìn, bạn có thể nghĩ rằng đây là mã đồng bộ vì bản in thứ hai đang đợi 1 giây để in “Xin chào lần nữa. ” sau “Xin chào thế giới. ”. Nhưng mã này thực sự không đồng bộ
quân đoàn
Bất kỳ hàm nào được định nghĩa là async def
đều là một coroutine như async/await
2 ở trên. Lưu ý rằng việc gọi hàm async/await
2 không giống như gói nó bên trong hàm async/await
4
Để chạy coroutine, asyncio cung cấp ba cơ chế chính
Hàm async/await
4 là điểm vào chính của thế giới không đồng bộ bắt đầu vòng lặp sự kiện và chạy coroutine
async/await
6 kết quả của quy trình đăng quang và chuyển điều khiển đến vòng lặp sự kiện
Đoạn mã trước vẫn đợi quy trình đăng ký async/await
7 kết thúc nên nó thực thi tác vụ 1 trong 1 giây và sau đó thực hiện tác vụ thứ hai sau khi đợi 2 giây
Để coroutine chạy đồng thời ta nên tạo task, đây là cơ chế thứ 3
- Hàm
async/await
8 được sử dụng để lên lịch cho coroutine thực thi
Đoạn mã trên hiện đang chạy đồng thời và quy trình đăng ký async/await
7 không còn chờ quy trình đăng ký async/await
7 kết thúc. Thay vì chạy cùng một quy trình với các tham số khác nhau đồng thời
Điều gì xảy ra như sau
Quy trình say_something[] bắt đầu với tác vụ đầu tiên của tham số [1 giây và một chuỗi “Nhiệm vụ 1”]. Nhiệm vụ này được gọi là aiohttp
1
Sau đó, nó tạm dừng việc thực thi quy trình đăng ký và đợi 1 giây để quy trình đăng ký async/await
7 kết thúc khi nó gặp từ khóa đang chờ. Nó trả về điều khiển cho vòng lặp sự kiện
Tương tự đối với tác vụ thứ hai, nó tạm dừng việc thực thi quy trình đăng ký và đợi 2 giây để quy trình đăng ký async/await
7 kết thúc khi gặp từ khóa đang chờ
Sau khi điều khiển aiohttp
1 trở lại vòng lặp sự kiện, vòng lặp sự kiện tiếp tục nhiệm vụ thứ hai [ aiohttp
5 ] vì aiohttp
6 vẫn chưa kết thúc
Hàm async/await
8 bao bọc hàm async/await
7 và làm cho nó chạy coroutine đồng thời như một tác vụ không đồng bộ. Như bạn có thể thấy, đoạn mã trên cho thấy nó chạy nhanh hơn trước 1 giây
Coroutine được lên lịch tự động để chạy trong vòng lặp sự kiện khi async/await
8 được gọi
Các tác vụ giúp bạn chạy đồng thời nhiều coroutine, nhưng đây không phải là cách duy nhất để đạt được đồng thời
Chạy các tác vụ đồng thời với asyncio. tập trung[]
Một cách khác để chạy đồng thời nhiều coroutine là sử dụng hàm requests
0. Hàm này lấy các coroutine làm đối số và chạy chúng đồng thời
Trong đoạn mã trước, thủ tục chúc mừng[] được thực hiện đồng thời hai lần
đối tượng chờ đợi
Một đối tượng được gọi là có thể chờ nếu nó có thể được sử dụng với từ khóa đang chờ. Có 3 loại đối tượng chờ đợi chính. quy trình, nhiệm vụ và tương lai
quân đoàn
Trong ví dụ trước, các hàm quy trình requests
1 và requests
2 được chờ đợi bởi quy trình quy trình requests
3
Giả sử bạn bỏ qua từ khóa đang chờ trước nhiều quy trình đăng ký. Sau đó, bạn sẽ nhận được lỗi sau. requests
4 không bao giờ được chờ đợi
nhiệm vụ
Để lên lịch cho một coroutine chạy trong vòng lặp sự kiện, chúng ta sử dụng hàm async/await
8
tương lai
Một requests
6 là một đối tượng có thể chờ ở mức độ thấp đại diện cho kết quả của một phép tính không đồng bộ. Nó được tạo bằng cách gọi hàm requests
7
Hết giờ
Sử dụng requests
8 để đặt thời gian chờ cho một đối tượng có thể chờ hoàn thành. Lưu ý rằng requests
9 ở đây là đối tượng chờ đợi. Điều này hữu ích nếu bạn muốn đưa ra một ngoại lệ nếu đối tượng chờ đợi mất quá nhiều thời gian để hoàn thành. Ngoại lệ như mongo-python
0
Thời gian chờ ở đây trong đối tượng requests
6 được đặt thành 1 giây mặc dù quy trình đăng ký mongo-python
2 mất 400 giây để hoàn thành
suy nghĩ cuối cùng
Trong hướng dẫn này, chúng tôi đã giới thiệu lập trình không đồng bộ trong Python với mô-đun tích hợp Async IO. Chúng tôi đã xác định quy trình, nhiệm vụ và tương lai là gì
Chúng tôi cũng đề cập đến cách chạy nhiều coroutine đồng thời theo nhiều cách khác nhau và xem cách mã đồng thời có thể là lựa chọn tốt nhất của bạn khi bạn cần tối ưu hóa hiệu suất cho một số tác vụ nhất định
Bạn muốn trở thành một phần của Cộng đồng Andela?
Với hơn 175.000 nhà công nghệ trong cộng đồng của chúng tôi, tại hơn 90 quốc gia, chúng tôi cam kết tạo ra các nhóm kỹ thuật từ xa đa dạng với những tài năng hàng đầu thế giới. Và các thành viên trong mạng lưới của chúng tôi thích trở thành một phần của cộng đồng tài năng, thông qua các hoạt động, lợi ích, sự cộng tác cũng như các cuộc gặp gỡ trực tuyến và ảo