câu trả lời
Petr Krampl là tốt nhất theo ý kiến của tôi, nhưng nhu cầu nhiều hơn để được nói về bản chất của các vòng lặp và làm thế nào để tối ưu hóa việc sử dụng các hệ thống . Người mới bắt đầu xảy ra khi chuỗi này có thể bị nhầm lẫn hơn bởi các lỗi logic và thuật toán trong câu hỏi và câu trả lời hiện có.
Đầu tiên, chúng ta hãy nhìn vào những gì mã của bạn không như bạn ban đầu đã viết nó:
while True:
test = 0
if test == 5:
break
test = test - 1
Nếu bạn nói while True
trong một bối cảnh vòng lặp, thường ý định của bạn là ở trong vòng lặp mãi mãi. Nếu đó không phải là ý định của bạn, bạn nên xem xét các tùy chọn khác cho cấu trúc của vòng lặp. Petr Krampl cho bạn thấy một cách hoàn toàn hợp lý để xử lý vấn đề này rõ ràng hơn với người khác có thể đọc mã của bạn. Ngoài ra, nó sẽ rõ ràng hơn với bạn vài tháng sau đó nếu bạn cần phải truy cập lại mã của bạn để thêm hoặc sửa chữa một cái gì đó. Mã được viết tốt là một phần của tài liệu của bạn. Thường có nhiều cách để làm mọi thứ, nhưng điều đó không làm cho tất cả các cách đều hợp lệ trong mọi ngữ cảnh. while true
là một ví dụ điển hình về điều này, đặc biệt trong ngữ cảnh này.
Tiếp theo, chúng tôi sẽ xem xét lỗi thuật toán trong mã ban đầu của bạn. Điều đầu tiên bạn làm trong vòng lặp là gán 0 đến test
. Điều tiếp theo bạn cần làm là kiểm tra xem giá trị của test
là 5, điều này sẽ không bao giờ xảy ra trừ khi bạn có nhiều chủ đề sửa đổi cùng một vị trí bộ nhớ. Luồng không nằm trong phạm vi của cuộc thảo luận này, nhưng đáng lưu ý rằng mã có thể hoạt động về mặt kỹ thuật, nhưng ngay cả với nhiều luồng sẽ bị thiếu, ví dụ: semaphores. Dù sao, bạn sẽ ngồi trong vòng lặp này mãi mãi bất kể thực tế là sentinel đang buộc một vòng lặp vô hạn.
Tuyên bố test = test - 1
là vô ích bất kể nó làm gì vì biến được đặt lại ở đầu vòng lặp tiếp theo của vòng lặp. Ngay cả khi bạn thay đổi nó thành test = 5
, vòng lặp sẽ vẫn vô hạn vì giá trị được đặt lại mỗi lần. Nếu bạn di chuyển câu lệnh khởi tạo bên ngoài vòng lặp, thì ít nhất nó sẽ có cơ hội thoát ra. Những gì bạn có thể đã dự định là một cái gì đó như thế này:
test = 0
while True:
test = test - 1
if test == 5:
break
Thứ tự của các câu lệnh trong vòng lặp phụ thuộc vào logic của chương trình của bạn.Nó sẽ làm việc theo một trong hai thứ, mặc dù, đó là điểm chính.
Vấn đề tiếp theo là lỗi logic có khả năng và có thể xảy ra bắt đầu từ 0, liên tục trừ đi 1, sau đó so sánh với số dương. Có, có những trường hợp điều này có thể thực sự là những gì bạn dự định làm miễn là bạn hiểu được các tác động, nhưng điều này rất có thể không phải là những gì bạn dự định. Phiên bản mới hơn của python sẽ không quấn quanh khi bạn đạt đến 'đáy' của phạm vi của một số nguyên như C và các ngôn ngữ khác. Nó sẽ cho phép bạn tiếp tục trừ 1 cho đến khi bạn đã lấp đầy bộ nhớ sẵn có trên hệ thống của mình hoặc ít nhất là những gì được phân bổ cho quá trình của bạn. Nhìn vào kịch bản sau đây và kết quả:
test = 0
while True:
test -= 1
if test % 100 == 0:
print "Test = %d" % test
if test == 5:
print "Test = 5"
break
trong đó sản xuất này:
Test = -100
Test = -200
Test = -300
Test = -400
...
Test = -21559000
Test = -21559100
Test = -21559200
Test = -21559300
...
Giá trị của test
sẽ không bao giờ là 5, vì vậy vòng lặp này sẽ không bao giờ thoát.
Để thêm vào câu trả lời Petr Krampl của, đây là một phiên bản có lẽ gần gũi hơn với những gì bạn thực sự có ý định ngoài việc thoát khỏi vòng lặp sau một thời gian nhất định:
import time
test = 0
timeout = 300 # [seconds]
timeout_start = time.time()
while time.time() < timeout_start + timeout:
if test == 5:
break
test -= 1
Nó vẫn sẽ không phá vỡ dựa trên giá trị của test
, nhưng đây là một vòng lặp hoàn toàn hợp lệ với điều kiện ban đầu hợp lý. Kiểm tra ranh giới tiếp theo có thể giúp bạn tránh việc thực hiện vòng lặp rất dài không có lý do, ví dụ: kiểm tra xem giá trị của phép thử có nhỏ hơn 5 khi nhập vòng lặp hay không, điều này sẽ ngay lập tức phá vỡ vòng lặp.
Một điều khác cần được đề cập là không có câu trả lời nào khác được giải quyết. Đôi khi bạn lặp lại như thế này, bạn có thể không muốn tiêu thụ CPU cho toàn bộ thời gian quy định. Ví dụ: giả sử bạn đang kiểm tra giá trị của thứ gì đó thay đổi mỗi giây. Nếu bạn không giới thiệu một số loại chậm trễ, bạn sẽ sử dụng mọi chu kỳ CPU có sẵn được phân bổ cho quá trình của bạn. Đó là tốt nếu nó là cần thiết, nhưng thiết kế tốt sẽ cho phép rất nhiều chương trình để chạy song song trên hệ thống của bạn mà không cần quá tải các nguồn lực sẵn có. Một câu lệnh ngủ đơn giản sẽ giải phóng phần lớn các chu kỳ CPU được phân bổ cho quá trình của bạn để các chương trình khác có thể làm việc.
Ví dụ sau không hữu ích lắm, nhưng nó thể hiện khái niệm. Giả sử bạn muốn in thứ gì đó mỗi giây. Một cách để làm điều đó sẽ là như thế này:
import time
tCurrent = time.time()
while True:
if time.time() >= tCurrent + 1:
print "Time = %d" % time.time()
tCurrent = time.time()
Kết quả sẽ là:
Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
Và việc sử dụng quá trình CPU sẽ trông như thế này:
Đó là một số lượng lớn việc sử dụng CPU để làm cơ bản không có công việc.Mã này rất đẹp với phần còn lại của hệ thống:
import time
tCurrent = time.time()
while True:
time.sleep(0.25) # sleep for 250 milliseconds
if time.time() >= tCurrent + 1:
print "Time = %d" % time.time()
tCurrent = time.time()
Kết quả là như nhau:
Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
và sử dụng CPU là bằng cách nào, cách thấp hơn:
Cảm ơn bạn làm việc này :) – Adilicious
tôi sử dụng 'timeit.default_timer', mà luôn luôn là đồng hồ chính xác nhất cho nền tảng này. Cụ thể, 'time.time' chỉ có độ chi tiết 1/60 s trên Windows, điều này có thể không đủ nếu bạn có thời gian chờ rất ngắn. Trên Python 3, cũng có 'time.monotonic',' time.perf_counter' và 'time.process_time', có thể tốt hơn (tôi chưa xử lý nhiều). – jpkotta
Có quá nhiều điều kiện để xử lý trong giải pháp này. Điều này sẽ được tối ưu hóa và 'while True' được thay thế bằng' while time.time()