Hồ sơ thống kê Python

Để cải thiện hiệu suất của các ứng dụng của bạn, bạn cần tiến hành một số loại phân tích động [chương trình, phần mềm, mã], còn được gọi là lập hồ sơ, để đo lường các chỉ số quan tâm. Một số liệu quan trọng đối với các nhà phát triển là thời gian – mã dành phần lớn thời gian của nó ở đâu?

Điều này có vẻ hiển nhiên, nhưng điều đáng chú ý là nếu bạn không lập hồ sơ để tối ưu hóa mã, bạn có thể loay hoay xung quanh các phần cải thiện mã mà bạn nghĩ có thể là nút thắt cổ chai. Tôi đã chứng kiến ​​mọi người dành hàng giờ đồng hồ để làm việc với một phần cụ thể trong mã của họ khi một hồ sơ đơn giản cho thấy phần mã đó đóng góp rất ít vào thời gian chạy tổng thể. Tôi thừa nhận rằng tôi đã làm điều này trước đây, tập trung vào các vòng lặp mà tôi nghĩ sẽ mất nhiều thời gian nhất mà không cần lập hồ sơ;

Các loại hồ sơ khác nhau [e. g. , dựa trên sự kiện, thống kê, công cụ, mô phỏng], được sử dụng trong các tình huống khác nhau. Trong bài viết này, tôi tập trung vào hai loại. xác định và thống kê. Hồ sơ xác định nắm bắt mọi tính toán của mã và tạo ra các hồ sơ rất chính xác, nhưng nó có thể làm chậm hiệu suất mã rất nhiều. Mặc dù bạn đạt được độ chính xác rất tốt với cấu hình, thời gian chạy tăng lên rất nhiều và bạn phải tự hỏi liệu cấu hình có ảnh hưởng xấu đến cách mã chạy hay không;

Mặt khác, lập hồ sơ thống kê lấy các “mẫu” định kỳ của các tính toán mã và sử dụng chúng làm đại diện cho hồ sơ của mã. Phương pháp này thường có rất ít ảnh hưởng đến hiệu suất mã, vì vậy bạn có thể nhận được một cấu hình rất gần với việc thực thi mã thực sự. Người ta phải tự hỏi về khoảng thời gian chính xác để có được cấu hình chính xác của ứng dụng trong khi không ảnh hưởng đến thời gian chạy. Thông thường, điều này có nghĩa là đặt khoảng thời gian thành các giá trị nhỏ hơn và nhỏ hơn để chụp chính xác cấu hình. Nếu khoảng thời gian trở nên quá nhỏ, thì nó gần như trở thành hồ sơ xác định và thời gian chạy sẽ tăng lên rất nhiều

Mặt khác, nếu mã của bạn mất nhiều thời gian để thực thi [e. g. , giờ hoặc ngày], việc lập hồ sơ xác định có thể là không thể vì việc tăng thời gian chạy là không thể chấp nhận được. Trong trường hợp này, hồ sơ thống kê là phù hợp vì khoảng thời gian dài hơn có sẵn để thực hiện mẫu

Trong bài viết này, tôi tập trung vào việc lập hồ sơ mã Python, chủ yếu là do thiếu hồ sơ Python hiện tại nhưng cũng bởi vì tôi nghĩ rằng việc lập hồ sơ mã Python, tạo hàm và sử dụng Numba để biên dịch các hàm này cho CPU hoặc GPU là một quy trình tốt giúp cải thiện

Để giúp minh họa một số công cụ bạn có thể sử dụng để cấu hình mã Python, tôi sẽ sử dụng một ví dụ về ứng dụng động lực học phân tử [MD] lý tưởng hóa. Tôi sẽ làm việc thông qua một số công cụ lập hồ sơ và sửa đổi mã theo cách hợp lý để lập hồ sơ tốt hơn. Phương pháp đầu tiên, và có lẽ được sử dụng nhiều nhất và linh hoạt nhất mà tôi muốn đề cập là lập hồ sơ “thủ công”.

Hồ sơ thủ công

Phương pháp lập hồ sơ thủ công khá đơn giản nhưng liên quan đến việc chèn các điểm thời gian vào mã của bạn. Các điểm thời gian bao quanh một phần mã và thu thập [các] tổng thời gian đã trôi qua cho phần đó, cũng như số lần phần đó được thực thi. Từ thông tin này, bạn có thể tính toán thời gian trôi qua trung bình. Các điểm thời gian có thể trải đều trong mã, vì vậy bạn có thể biết được mỗi phần của mã mất bao nhiêu thời gian. Thời gian đã trôi qua được in khi kết thúc quá trình thực hiện, giúp bạn biết được mình nên tập trung nỗ lực vào đâu để cải thiện hiệu suất

Một ưu điểm chính của phương pháp này là chi phí chung thấp. Ngoài ra, bạn có thể kiểm soát phần nào của mã được tính thời gian [bạn không phải lập hồ sơ cho toàn bộ mã]. Một nhược điểm là bạn phải thiết lập mã của mình bằng cách chèn các điểm thời gian xuyên suốt. Tuy nhiên, việc chèn các điểm này không khó

Một cách dễ dàng để thực hiện điều này là sử dụng mô-đun thời gian Python. Đoạn mã đơn giản từ một bài viết trên trang web Better Programming [ví dụ 16] được hiển thị trong Liệt kê 1. Mã chỉ cần gọi thời gian hiện tại trước và sau một phần mã quan tâm. Sự khác biệt là thời gian đã trôi qua hoặc lượng thời gian cần thiết để thực thi phần mã đó

Liệt kê 1. Thời gian thực hiện

import time
 
start_time = time.time[]
# Code to check follows
a, b = 1,2
c = a + b
# Code to check ends
end_time = time.time[]
time_taken = [end_time- start_time]
 
print[" Time taken in seconds: {0} s"].format[time_taken_in_micro]

Nếu một phần mã được gọi lặp lại, chỉ cần tính tổng thời gian đã trôi qua cho phần đó và tính tổng số lần phần đó được sử dụng; . Nếu số lượng cuộc gọi đủ lớn, bạn có thể thực hiện một số thống kê mô tả nhanh và tính giá trị trung bình, trung bình, phương sai, tối thiểu, tối đa và độ lệch

hồ sơ c

cProfile là một trình lược tả xác định cho Python và được đề xuất “… cho hầu hết người dùng. ” Nói chung, nó tạo ra một tập hợp thống kê liệt kê tổng thời gian dành cho một số phần nhất định của mã, cũng như tần suất phần mã được gọi

cProfile, như gợi ý tên, được viết bằng C dưới dạng phần mở rộng của Python và có trong Python 3 tiêu chuẩn, giúp duy trì chi phí thấp, do đó, trình lược tả không ảnh hưởng nhiều đến lượng thời gian

cProfile đưa ra một số thống kê về mã kiểm tra

  • ncalls – số lần gọi đến phần mã
  • tottime– tổng thời gian dành cho chức năng nhất định [không bao gồm thời gian được thực hiện trong các cuộc gọi đến chức năng con]
  • percall – tottime chia cho ncalls
  • cumtime – thời gian tích lũy dành cho chức năng cụ thể, bao gồm tất cả các chức năng con
  • percall – cumtime chia cho ncalls

cProfile cũng xuất tên tệp của mã, trong trường hợp có nhiều tệp liên quan, cũng như số dòng của hàm [lineno]

Chạy cProfile khá đơn giản

$ python -m cProfile -s cumtime script.py

Phần đầu tiên của lệnh yêu cầu Python sử dụng mô-đun cProfile. Đầu ra từ cProfile được sắp xếp [-s] theo cumtime [thời gian tích lũy]. Tùy chọn cuối cùng trên dòng lệnh là mã Python quan tâm. cProfile cũng có tùy chọn [-o] để gửi số liệu thống kê tới tệp đầu ra thay vì thiết bị xuất chuẩn. Liệt kê 2 là mẫu của một vài dòng đầu tiên từ cProfile trên một biến thể của mã MD

Chủ Đề