Python tiếp tục sau thời gian

Trì hoãn mã (còn được gọi là ngủ) đúng như tên gọi của nó, việc trì hoãn thực thi mã trong một khoảng thời gian. Nhu cầu trì hoãn mã phổ biến nhất là khi chúng tôi đang đợi một số quy trình khác kết thúc để chúng tôi có thể làm việc với kết quả của quy trình đó. Trong các hệ thống đa luồng, một luồng có thể muốn đợi một luồng khác hoàn thành thao tác để tiếp tục làm việc với kết quả đó

Một ví dụ khác có thể làm giảm bớt căng thẳng cho máy chủ mà chúng tôi đang làm việc cùng. Ví dụ: trong khi quét web (về mặt đạo đức) và tuân theo Điều khoản dịch vụ của trang web được đề cập, tuân theo tệp

14:33:55.282626
14:34:00.287661
9 - bạn rất có thể muốn trì hoãn việc thực hiện từng yêu cầu để không làm quá tải tài nguyên của máy chủ

Nhiều yêu cầu, được thực hiện liên tiếp nhanh chóng, tùy thuộc vào máy chủ được đề cập, có thể nhanh chóng chiếm lấy tất cả các kết nối miễn phí và trở thành một cuộc tấn công DoS một cách hiệu quả. Để có không gian thở, cũng như để đảm bảo rằng chúng tôi không tác động tiêu cực đến người dùng trang web hoặc chính trang web - chúng tôi sẽ giới hạn số lượng yêu cầu được gửi bằng cách trì hoãn từng yêu cầu

Một học sinh đang chờ kết quả kỳ thi có thể tức giận làm mới trang web của trường họ, chờ đợi tin tức. Ngoài ra, họ có thể viết một đoạn script kiểm tra xem trang web có gì mới không. Theo một nghĩa nào đó, độ trễ mã về mặt kỹ thuật có thể trở thành lập lịch mã với điều kiện kết thúc và vòng lặp hợp lệ - giả sử rằng cơ chế độ trễ tại chỗ không bị chặn

Trong bài viết này, chúng ta sẽ xem cách trì hoãn thực thi mã trong Python - còn được gọi là ngủ

Một trong những giải pháp phổ biến nhất cho vấn đề này là chức năng

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
0 của mô-đun
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
1 tích hợp. Nó chấp nhận số giây bạn muốn quy trình ngủ - không giống như nhiều ngôn ngữ khác dựa trên mili giây

import datetime
import time

print(datetime.datetime.now().time())
time.sleep(5)
print(datetime.datetime.now().time())

Kết quả này trong

14:33:55.282626
14:34:00.287661

Khá rõ ràng, chúng ta có thể thấy độ trễ 5 giây giữa hai câu lệnh

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
2, với độ chính xác khá cao - xuống đến chữ số thập phân thứ hai. Nếu bạn muốn ngủ ít hơn 1 giây, bạn cũng có thể dễ dàng chuyển các số không nguyên

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
14:46:16.198404
14:46:16.448840
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
14:46:16.448911
14:46:17.730291

Mặc dù vậy, hãy nhớ rằng với 2 chữ số thập phân, thời lượng ngủ có thể không chính xác, đặc biệt là vì nó khó kiểm tra, do thực tế là các câu lệnh

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
2 cũng mất một khoảng thời gian (có thể thay đổi) để thực thi

Tuy nhiên, có một nhược điểm lớn đối với chức năng

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4, rất đáng chú ý trong môi trường đa luồng

thời gian. ngủ () đang chặn

Nó nắm bắt luồng đang bật và chặn luồng đó trong suốt thời gian ngủ. Điều này làm cho nó không phù hợp với thời gian chờ đợi lâu hơn, vì nó làm tắc luồng của bộ xử lý trong khoảng thời gian đó. Ngoài ra, điều này làm cho nó không phù hợp với Ứng dụng không đồng bộ và phản ứng, đôi khi yêu cầu phản hồi và dữ liệu thời gian thực

Một điều khác cần lưu ý về

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4 là bạn không thể dừng nó lại. Sau khi nó bắt đầu, bạn không thể hủy nó từ bên ngoài mà không chấm dứt toàn bộ chương trình hoặc nếu bạn khiến chính phương thức
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
0 đưa ra một ngoại lệ, điều này sẽ dừng nó

Lập trình không đồng bộ và phản ứng

Lập trình không đồng bộ xoay quanh việc thực thi song song - trong đó một tác vụ có thể được thực thi và kết thúc độc lập với luồng chính

Trong Lập trình đồng bộ - nếu Chức năng A gọi Chức năng B, nó sẽ dừng thực thi cho đến khi Chức năng B kết thúc thực thi, sau đó Chức năng A có thể tiếp tục

Trong Lập trình không đồng bộ - nếu Hàm A gọi Hàm B, bất kể sự phụ thuộc của nó vào kết quả từ Hàm B, cả hai có thể thực thi cùng một lúc và nếu cần, hãy đợi hàm kia kết thúc để sử dụng kết quả của nhau

Lập trình phản ứng là một tập hợp con của Lập trình không đồng bộ, kích hoạt thực thi mã một cách phản ứng, khi dữ liệu được hiển thị, bất kể chức năng được cho là xử lý nó có đang bận hay không. Lập trình phản ứng phụ thuộc rất nhiều vào Kiến trúc hướng thông báo (trong đó thông báo thường là một sự kiện hoặc lệnh)

Cả ứng dụng Không đồng bộ và Phản ứng đều là những ứng dụng bị chặn mã nhiều - vì vậy sử dụng thứ gì đó như

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4 không phù hợp với chúng. Chúng ta hãy xem một số tùy chọn trì hoãn mã không chặn

Trì hoãn mã với asyncio. ngủ()

Asyncio là một thư viện Python dành riêng cho việc viết mã đồng thời và sử dụng cú pháp

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
8/
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
9, cú pháp này có thể quen thuộc với các nhà phát triển đã sử dụng nó trong các ngôn ngữ khác

Hãy cài đặt mô-đun qua

14:46:16.198404
14:46:16.448840
0

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
8

Sau khi cài đặt, chúng tôi có thể đưa nó vào tập lệnh của mình và viết lại chức năng của chúng tôi

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
0

Khi làm việc với

14:46:16.198404
14:46:16.448840
2, chúng tôi đánh dấu các chức năng chạy không đồng bộ là
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
8 và
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
9 là kết quả của các hoạt động chẳng hạn như
14:46:16.198404
14:46:16.448840
5 sẽ kết thúc vào một thời điểm nào đó trong tương lai

Tương tự như ví dụ trước, thao tác này sẽ in hai lần, cách nhau 5 giây

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
5

Hãy xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, tiêu chuẩn được ngành chấp nhận và bao gồm bảng gian lận. Dừng các lệnh Git trên Google và thực sự tìm hiểu nó

Mặc dù vậy, điều này không thực sự minh họa lợi ích của việc sử dụng

14:46:16.198404
14:46:16.448840
5. Hãy viết lại ví dụ để chạy song song một số tác vụ, trong đó sự khác biệt này rõ ràng hơn rất nhiều

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
7

Ở đây, chúng ta có một hàm

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
8, mô phỏng một tác vụ tốn nhiều công sức mất 5 giây để hoàn thành. Sau đó, sử dụng
14:46:16.198404
14:46:16.448840
2, chúng tôi tạo nhiều tác vụ. Tuy nhiên, mỗi tác vụ có thể chạy không đồng bộ, chỉ khi chúng ta gọi chúng không đồng bộ. Nếu chúng ta chạy chúng tuần tự, chúng cũng sẽ thực thi tuần tự

Để gọi chúng song song, chúng tôi sử dụng hàm

14:46:16.198404
14:46:16.448840
9, tốt, tập hợp các tác vụ và thực thi chúng

14:33:55.282626
14:34:00.287661
0

Tất cả chúng đều được thực hiện cùng một lúc và thời gian chờ đợi của ba trong số chúng không phải là 15 giây - mà là 5

Mặt khác, nếu chúng tôi chỉnh sửa mã này để sử dụng

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4 thay thế

14:33:55.282626
14:34:00.287661
1

Chúng tôi sẽ đợi 5 giây giữa mỗi câu lệnh

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
2

14:33:55.282626
14:34:00.287661
2

Lớp

print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
2 là một lớp
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
3, chỉ có thể chạy và thực hiện các hoạt động sau một khoảng thời gian nhất định đã trôi qua. Tuy nhiên, hành vi này chính xác là những gì chúng tôi đang tìm kiếm, hơi quá mức cần thiết khi sử dụng các
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
3 để trì hoãn mã nếu bạn chưa làm việc với một hệ thống đa luồng

Lớp

print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
2 cần tới
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
6 và có thể tạm dừng qua
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
7. Hàm tạo của nó chấp nhận một số nguyên, biểu thị số giây phải đợi trước khi thực thi tham số thứ hai - một hàm

Hãy tạo một hàm và thực thi nó thông qua một

print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
2

14:33:55.282626
14:34:00.287661
3

Kết quả này trong

14:33:55.282626
14:34:00.287661
4

Phương thức

print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
7 thực sự hữu ích nếu chúng ta có nhiều hàm đang chạy và chúng ta muốn hủy thực thi một hàm, dựa trên kết quả của một hàm khác hoặc trên một điều kiện khác

Hãy viết một hàm

14:46:16.448911
14:46:17.730291
0, gọi cả hai hàm
14:46:16.448911
14:46:17.730291
1 và
14:46:16.448911
14:46:17.730291
2.
14:46:16.448911
14:46:17.730291
1 được gọi là nguyên trạng - và trả về một số nguyên ngẫu nhiên trong khoảng từ 1 đến 10, mô phỏng thời gian cần thiết để chạy hàm đó

14:46:16.448911
14:46:17.730291
2 được gọi thông qua một
print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
2 và nếu kết quả của
14:46:16.448911
14:46:17.730291
1 lớn hơn
14:46:16.448911
14:46:17.730291
7, thì
14:46:16.448911
14:46:17.730291
2 sẽ bị hủy bỏ, ngược lại nếu
14:46:16.448911
14:46:17.730291
1 chạy trong khoảng thời gian "dự kiến" nhỏ hơn
14:46:16.448911
14:46:17.730291
7 - thì
14:46:16.448911
14:46:17.730291
2 sẽ chạy sau khi bộ đếm thời gian kết thúc

14:33:55.282626
14:34:00.287661
5

Chạy mã này nhiều lần sẽ trông giống như dòng

14:33:55.282626
14:34:00.287661
6

Trì hoãn mã với sự kiện

Lớp

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
82 có thể được sử dụng để tạo các sự kiện. Một sự kiện đơn lẻ có thể được "lắng nghe" bởi nhiều chủ đề. Hàm
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
83 chặn luồng đang bật, trừ khi
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
84. Sau khi bạn
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
85 một Sự kiện, tất cả các chủ đề đang chờ sẽ được đánh thức và
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
83 trở thành không bị chặn

Điều này có thể được sử dụng để đồng bộ hóa các luồng - tất cả chúng chồng chất lên nhau và

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
87 cho đến khi một Sự kiện nhất định được đặt, sau đó, chúng có thể ra lệnh cho luồng của chúng

Hãy tạo một phương thức

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
88 và chạy nó nhiều lần trên các luồng khác nhau. Mỗi người phục vụ bắt đầu làm việc vào một thời điểm nhất định và kiểm tra xem họ có còn đến giờ mỗi giây hay không, ngay trước khi họ gọi món, quá trình này mất một giây để hoàn thành. Họ sẽ làm việc cho đến khi Sự kiện được thiết lập - hay đúng hơn là thời gian làm việc của họ đã hết

Mỗi người phục vụ sẽ có luồng riêng của họ, trong khi quản lý nằm trong luồng chính và gọi khi mọi người có thể gọi về nhà. Vì hôm nay họ cảm thấy hào phóng hơn, họ sẽ cắt giảm thời gian làm việc và để những người phục vụ về nhà sau 4 giây làm việc

14:33:55.282626
14:34:00.287661
7

Chạy mã này dẫn đến

14:33:55.282626
14:34:00.287661
8

Sự kiện

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
89 được sử dụng ở đây để đồng bộ hóa hai luồng và kiểm soát khi nào chúng hoạt động và khi nào không, trì hoãn việc thực thi mã theo thời gian đã đặt giữa các lần kiểm tra

Phần kết luận

Trong hướng dẫn này, chúng ta đã xem xét một số cách để trì hoãn việc thực thi mã trong Python - mỗi cách áp dụng cho một ngữ cảnh và yêu cầu khác nhau

Phương pháp

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4 thông thường khá hữu ích cho hầu hết các ứng dụng, tuy nhiên, nó không thực sự tối ưu trong thời gian chờ đợi lâu, không được sử dụng phổ biến để lập lịch trình đơn giản và đang chặn

Sử dụng

14:46:16.198404
14:46:16.448840
2, chúng tôi có phiên bản không đồng bộ của
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
4 mà chúng tôi có thể
print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
9

Lớp

print(datetime.datetime.now().time())
time.sleep(1.28)
print(datetime.datetime.now().time())
2 trì hoãn việc thực thi mã và có thể bị hủy nếu cần

Lớp

print(datetime.datetime.now().time())
time.sleep(0.25)
print(datetime.datetime.now().time())
82 tạo các sự kiện mà nhiều luồng có thể lắng nghe và phản hồi tương ứng, trì hoãn việc thực thi mã cho đến khi một sự kiện nhất định được đặt