Trình biên dịch Python¶
Source code: Lib/profile.py và Lib/pstats.py
Giới thiệu về hồ sơ¶
cProfile và profile cung cấp deterministic profiling cho các chương trình Python. Zz003zz là một tập hợp số liệu thống kê mô tả tần suất và thời gian thực hiện các phần khác nhau của chương trình. Những thống kê này có thể được định dạng thành báo cáo thông qua mô-đun pstats.
Thư viện chuẩn Python cung cấp hai cách triển khai khác nhau của cùng một giao diện lược tả:
cProfileđược khuyên dùng cho hầu hết người dùng; đó là một tiện ích mở rộng C với chi phí hợp lý giúp nó phù hợp để lập cấu hình các chương trình chạy dài. Dựa trênlsprof, do Brett Rosen và Ted Czotter đóng góp.profile, một mô-đun Python thuần túy có giao diện được bắt chước bởicProfile, nhưng bổ sung thêm chi phí đáng kể cho các chương trình được định hình. Nếu bạn đang cố gắng mở rộng trình lược tả theo một cách nào đó, tác vụ có thể dễ dàng hơn với mô-đun này. Được thiết kế và viết ban đầu bởi Jim Roskind.
Ghi chú
Các mô-đun trình hồ sơ được thiết kế để cung cấp hồ sơ thực thi cho một chương trình nhất định, không nhằm mục đích đo điểm chuẩn (vì mục đích đó, có timeit để có kết quả chính xác hợp lý). Điều này đặc biệt áp dụng cho việc đo điểm chuẩn của mã Python so với mã C: trình lược tả đưa ra chi phí chung cho mã Python, nhưng không áp dụng cho các hàm cấp C và do đó, mã C có vẻ nhanh hơn bất kỳ mã Python nào.
Hướng dẫn sử dụng tức thì¶
Phần này được cung cấp cho những người dùng “không muốn đọc hướng dẫn”. Nó cung cấp một cái nhìn tổng quan rất ngắn gọn và cho phép người dùng nhanh chóng thực hiện lập hồ sơ trên một ứng dụng hiện có.
Để cấu hình một hàm có một đối số duy nhất, bạn có thể thực hiện
nhập cProfile
nhập lại
cProfile.run('re.compile("foo|bar")')
(Sử dụng profile thay vì cProfile nếu cái sau không có sẵn trên hệ thống của bạn.)
Hành động trên sẽ chạy re.compile() và in kết quả hồ sơ như sau:
214 lệnh gọi hàm (207 lệnh gọi nguyên thủy) trong 0,002 giây
Sắp xếp theo: thời gian tích lũy
ncalls tottime percall tên tệp cumtime percall:lineno(function)
1 0,000 0,000 0,002 0,002 {phương thức dựng sẵn buildins.exec}
1 0,000 0,000 0,001 0,001 <string>:1(<module>)
1 0,000 0,000 0,001 0,001 __init__.py:250(biên dịch)
1 0,000 0,000 0,001 0,001 __init__.py:289(_compile)
1 0,000 0,000 0,000 0,000 _compiler.py:759(biên dịch)
1 0,000 0,000 0,000 0,000 _parser.py:937(phân tích cú pháp)
1 0,000 0,000 0,000 0,000 _compiler.py:598(_code)
1 0,000 0,000 0,000 0,000 _parser.py:435(_parse_sub)
Dòng đầu tiên cho biết 214 cuộc gọi đã được theo dõi. Trong số các cuộc gọi đó, 207 cuộc gọi là primitive, nghĩa là cuộc gọi không được thực hiện thông qua đệ quy. Dòng tiếp theo: Ordered by: cumulative time cho biết đầu ra được sắp xếp theo các giá trị cumtime. Các tiêu đề cột bao gồm:
- ncall
về số lượng cuộc gọi.
- toàn thời gian
trong tổng thời gian dành cho chức năng nhất định (và không bao gồm thời gian thực hiện khi gọi đến các chức năng phụ)
- cuộc gọi
là thương của
tottimechia choncalls- xuất tinh
là thời gian tích lũy dành cho chức năng này và tất cả các chức năng con (từ khi gọi đến khi thoát). Con số này chính xác even cho hàm đệ quy.
- cuộc gọi
là thương của
cumtimechia cho các lệnh gọi nguyên thủy- tên tập tin:lineno(chức năng)
cung cấp dữ liệu tương ứng của từng chức năng
Khi có hai số trong cột đầu tiên (ví dụ 3/1), điều đó có nghĩa là hàm được đệ quy. Giá trị thứ hai là số lượng cuộc gọi nguyên thủy và giá trị thứ nhất là tổng số cuộc gọi. Lưu ý rằng khi hàm không lặp lại, hai giá trị này giống nhau và chỉ in một hình duy nhất.
Thay vì in kết quả khi kết thúc quá trình chạy hồ sơ, bạn có thể lưu kết quả vào một tệp bằng cách chỉ định tên tệp cho hàm run():
nhập cProfile
nhập lại
cProfile.run('re.compile("foo|bar")', 'restats')
Lớp pstats.Stats đọc kết quả hồ sơ từ một tệp và định dạng chúng theo nhiều cách khác nhau.
Các tệp cProfile và profile cũng có thể được gọi dưới dạng tập lệnh để cấu hình tập lệnh khác. Ví dụ:
python -m cProfile [-o đầu ra_file] [-s sắp xếp_order] (-m mô-đun | myscript.py)
- -o <output_file>¶
Ghi kết quả hồ sơ vào một tập tin thay vì vào thiết bị xuất chuẩn.
- -s <sort_order>¶
Chỉ định một trong các giá trị sắp xếp
sort_stats()để sắp xếp đầu ra theo. Điều này chỉ áp dụng khi-okhông được cung cấp.
- -m <module>¶
Chỉ định rằng một mô-đun đang được cấu hình thay vì tập lệnh.
Added in version 3.7: Đã thêm tùy chọn
-mvàocProfile.Added in version 3.8: Đã thêm tùy chọn
-mvàoprofile.
Lớp Stats của mô-đun pstats có nhiều phương thức khác nhau để thao tác và in dữ liệu được lưu vào tệp kết quả hồ sơ:
nhập pstat
từ pstats nhập SortKey
p = pstats.Stats('restats')
p.strip_dirs().sort_stats(-1).print_stats()
Phương thức strip_dirs() đã xóa đường dẫn không liên quan khỏi tất cả các tên mô-đun. Phương thức sort_stats() đã sắp xếp tất cả các mục theo chuỗi mô-đun/dòng/tên tiêu chuẩn được in. Phương pháp print_stats() in ra tất cả số liệu thống kê. Bạn có thể thử các cuộc gọi sắp xếp sau:
p.sort_stats(SortKey.NAME)
p.print_stats()
Cuộc gọi đầu tiên sẽ thực sự sắp xếp danh sách theo tên hàm và cuộc gọi thứ hai sẽ in ra số liệu thống kê. Sau đây là một số lệnh gọi thú vị để thử nghiệm:
p.sort_stats(SortKey.CUMULATIVE).print_stats(10)
Thao tác này sắp xếp cấu hình theo thời gian tích lũy trong một hàm và sau đó chỉ in mười dòng quan trọng nhất. Nếu bạn muốn hiểu thuật toán nào đang tiêu tốn nhiều thời gian thì dòng trên là những gì bạn sẽ sử dụng.
Nếu bạn muốn xem hàm nào lặp nhiều và tốn nhiều thời gian, bạn sẽ làm:
p.sort_stats(SortKey.TIME).print_stats(10)
để sắp xếp theo thời gian dành cho mỗi chức năng, sau đó in số liệu thống kê cho 10 chức năng hàng đầu.
Bạn cũng có thể thử:
p.sort_stats(SortKey.FILENAME).print_stats('__init__')
Thao tác này sẽ sắp xếp tất cả số liệu thống kê theo tên tệp và sau đó in ra số liệu thống kê chỉ cho các phương thức init của lớp (vì chúng được đánh vần bằng __init__ trong đó). Là một ví dụ cuối cùng, bạn có thể thử:
p.sort_stats(SortKey.TIME, SortKey.CUMULATIVE).print_stats(.5, 'init')
Dòng này sắp xếp số liệu thống kê với khóa chính là thời gian và khóa phụ là thời gian tích lũy, sau đó in ra một số số liệu thống kê. Cụ thể, danh sách trước tiên được chọn lọc xuống còn 50% (re: .5) kích thước ban đầu của nó, sau đó chỉ các dòng chứa init được duy trì và danh sách phụ đó được in.
Nếu bạn thắc mắc những hàm nào được gọi là các hàm trên thì bây giờ bạn có thể (p vẫn được sắp xếp theo tiêu chí cuối cùng) thực hiện:
p.print_callers(.5, 'init')
và bạn sẽ nhận được danh sách người gọi cho từng chức năng được liệt kê.
Nếu bạn muốn có nhiều chức năng hơn, bạn sẽ phải đọc hướng dẫn sử dụng hoặc đoán xem các chức năng sau đây làm gì:
p.print_callees()
p.add('khởi động lại')
Được gọi dưới dạng tập lệnh, mô-đun pstats là một trình duyệt thống kê để đọc và kiểm tra kết xuất hồ sơ. Nó có giao diện hướng dòng đơn giản (được triển khai bằng cmd) và trợ giúp tương tác.
Tham khảo mô-đun profile và cProfile¶
Cả hai mô-đun profile và cProfile đều cung cấp các chức năng sau:
- profile.run(command, filename=None, sort=-1)¶
Hàm này nhận một đối số duy nhất có thể được truyền cho hàm
exec()và một tên tệp tùy chọn. Trong mọi trường hợp, thói quen này thực thi:exec(lệnh, __main__.__dict__, __main__.__dict__)
và thu thập số liệu thống kê hồ sơ từ việc thực hiện. Nếu không có tên tệp thì hàm này sẽ tự động tạo một phiên bản
Statsvà in một báo cáo hồ sơ đơn giản. Nếu giá trị sắp xếp được chỉ định, giá trị đó sẽ được chuyển đến phiên bảnStatsnày để kiểm soát cách sắp xếp kết quả.
- profile.runctx(command, globals, locals, filename=None, sort=-1)¶
Hàm này tương tự như
run(), với các đối số được thêm vào để cung cấp ánh xạ toàn cục và cục bộ cho chuỗi command. Thói quen này thực thi:exec(lệnh, toàn cục, cục bộ)
và thu thập số liệu thống kê hồ sơ như trong hàm
run()ở trên.
- class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)¶
Lớp này thường chỉ được sử dụng nếu cần kiểm soát hồ sơ chính xác hơn những gì hàm
cProfile.run()cung cấp.Bộ hẹn giờ tùy chỉnh có thể được cung cấp để đo thời gian chạy mã thông qua đối số timer. Đây phải là hàm trả về một số duy nhất biểu thị thời gian hiện tại. Nếu số là số nguyên, timeunit chỉ định một hệ số chỉ định khoảng thời gian của từng đơn vị thời gian. Ví dụ: nếu bộ hẹn giờ trả về thời gian được đo bằng hàng nghìn giây thì đơn vị thời gian sẽ là
.001.Sử dụng trực tiếp lớp
Profilecho phép định dạng kết quả hồ sơ mà không cần ghi dữ liệu hồ sơ vào tệpnhập cProfile, pstats, io từ pstats nhập SortKey pr = cProfile.Profile() pr.enable() # ... làm điều gì đó ... pr.disable() s = io.StringIO() sắp xếp = SortKey.CUMULATIVE ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats() print(s.getvalue())
Lớp
Profilecũng có thể được sử dụng làm trình quản lý bối cảnh (chỉ được hỗ trợ trong mô-đuncProfile. Xem Các loại trình quản lý bối cảnh):nhập cProfile với cProfile.Profile() là pr: # ... làm điều gì đó ... pr.print_stats()
Thay đổi trong phiên bản 3.8: Đã thêm hỗ trợ quản lý bối cảnh.
- enable()¶
Bắt đầu thu thập dữ liệu hồ sơ. Chỉ có ở
cProfile.
- disable()¶
Ngừng thu thập dữ liệu hồ sơ. Chỉ có ở
cProfile.
- create_stats()¶
Dừng thu thập dữ liệu hồ sơ và ghi lại kết quả nội bộ dưới dạng hồ sơ hiện tại.
- print_stats(sort=-1)¶
Tạo một đối tượng
Statsdựa trên hồ sơ hiện tại và in kết quả ra thiết bị xuất chuẩn.Tham số sort chỉ định thứ tự sắp xếp của số liệu thống kê được hiển thị. Nó chấp nhận một khóa đơn hoặc một bộ khóa để cho phép sắp xếp nhiều cấp độ, như trong
Stats.sort_stats.Added in version 3.13:
print_stats()hiện chấp nhận một bộ khóa.
- dump_stats(filename)¶
Ghi kết quả của profile hiện tại vào filename.
- runctx(cmd, globals, locals)¶
Lập hồ sơ cmd qua
exec()với môi trường cục bộ và toàn cầu được chỉ định.
- runcall(func, /, *args, **kwargs)¶
Hồ sơ
func(*args, **kwargs)
Lưu ý rằng việc lập hồ sơ sẽ chỉ hoạt động nếu lệnh/hàm được gọi thực sự trả về. Nếu trình thông dịch bị chấm dứt (ví dụ: thông qua lệnh gọi sys.exit() trong quá trình thực thi lệnh/chức năng được gọi) thì sẽ không có kết quả lược tả nào được in.
Lớp Stats¶
Việc phân tích dữ liệu hồ sơ được thực hiện bằng lớp Stats.
- class pstats.Stats(*filenames or profile, stream=sys.stdout)¶
Hàm tạo lớp này tạo một phiên bản của "đối tượng thống kê" từ filename (hoặc danh sách tên tệp) hoặc từ một phiên bản
Profile. Đầu ra sẽ được in ra luồng được chỉ định bởi stream.Tệp được hàm tạo ở trên chọn phải được tạo bởi phiên bản tương ứng của
profilehoặccProfile. Cụ thể, khả năng tương thích tệp no được đảm bảo với các phiên bản trong tương lai của trình lược tả này và không có khả năng tương thích với các tệp do các trình lược tả khác tạo ra hoặc cùng một trình lược tả đó chạy trên một hệ điều hành khác. Nếu một số tệp được cung cấp, tất cả số liệu thống kê cho các chức năng giống nhau sẽ được hợp nhất để có thể xem xét cái nhìn tổng thể về một số quy trình trong một báo cáo. Nếu các tệp bổ sung cần được kết hợp với dữ liệu trong đối tượngStatshiện có, có thể sử dụng phương thứcadd().Thay vì đọc dữ liệu hồ sơ từ một tệp, đối tượng
cProfile.Profilehoặcprofile.Profilecó thể được sử dụng làm nguồn dữ liệu hồ sơ.Các đối tượng
Statscó các phương thức sau:- strip_dirs()¶
Phương thức này dành cho lớp
Statssẽ xóa tất cả thông tin đường dẫn hàng đầu khỏi tên tệp. Nó rất hữu ích trong việc giảm kích thước của bản in để vừa với (gần) 80 cột. Phương pháp này sửa đổi đối tượng và thông tin bị loại bỏ sẽ bị mất. Sau khi thực hiện thao tác dải, đối tượng được coi là có các mục nhập theo thứ tự "ngẫu nhiên", giống như ngay sau khi khởi tạo và tải đối tượng. Nếustrip_dirs()khiến hai tên hàm không thể phân biệt được (chúng nằm trên cùng một dòng của cùng một tên tệp và có cùng tên hàm), thì số liệu thống kê cho hai mục này sẽ được tích lũy vào một mục duy nhất.
- add(*filenames)¶
Phương thức này của lớp
Statstích lũy thông tin lược tả bổ sung vào đối tượng lược tả hiện tại. Các đối số của nó phải đề cập đến tên tệp được tạo bởi phiên bản tương ứng củaprofile.run()hoặccProfile.run(). Thống kê cho các hàm có tên giống hệt nhau (re: file, dòng, tên) được tự động tích lũy vào thống kê hàm đơn.
- dump_stats(filename)¶
Lưu dữ liệu được tải vào đối tượng
Statsvào một tệp có tên filename. Tệp được tạo nếu nó không tồn tại và bị ghi đè nếu nó đã tồn tại. Điều này tương đương với phương thức cùng tên trên lớpprofile.ProfilevàcProfile.Profile.
- sort_stats(*keys)¶
Phương thức này sửa đổi đối tượng
Statsbằng cách sắp xếp nó theo tiêu chí được cung cấp. Đối số có thể là một chuỗi hoặc một enum SortKey xác định cơ sở của một loại sắp xếp (ví dụ:'time','name',SortKey.TIMEhoặcSortKey.NAME). Đối số enum SortKey có lợi thế hơn đối số chuỗi ở chỗ nó mạnh hơn và ít xảy ra lỗi hơn.Khi có nhiều hơn một khóa được cung cấp thì các khóa bổ sung sẽ được sử dụng làm tiêu chí phụ khi có sự bằng nhau trong tất cả các khóa được chọn trước chúng. Ví dụ:
sort_stats(SortKey.NAME, SortKey.FILE)sẽ sắp xếp tất cả các mục theo tên hàm của chúng và giải quyết tất cả các mối quan hệ (tên hàm giống hệt nhau) bằng cách sắp xếp theo tên tệp.Đối với đối số chuỗi, có thể sử dụng chữ viết tắt cho bất kỳ tên khóa nào, miễn là chữ viết tắt đó rõ ràng.
Sau đây là chuỗi hợp lệ và SortKey:
Đối số chuỗi hợp lệ
Arg enum hợp lệ
Ý nghĩa
'calls'SortKey.CALLS
số cuộc gọi
'cumulative'SortKey.CUMULATIVE
thời gian tích lũy
'cumtime'không áp dụng
thời gian tích lũy
'file'không áp dụng
tên tập tin
'filename'SortKey.FILENAME
tên tập tin
'module'không áp dụng
tên tập tin
'ncalls'không áp dụng
số cuộc gọi
'pcalls'SortKey.PCALLS
số cuộc gọi nguyên thủy
'line'SortKey.LINE
số dòng
'name'SortKey.NAME
tên hàm
'nfl'SortKey.NFL
tên/tập tin/dòng
'stdname'SortKey.STDNAME
tên tiêu chuẩn
'time'SortKey.TIME
thời gian nội bộ
'tottime'không áp dụng
thời gian nội bộ
Lưu ý rằng tất cả các loại thống kê đều theo thứ tự giảm dần (đặt các mục tiêu tốn nhiều thời gian nhất lên đầu tiên), trong đó tìm kiếm tên, tệp và số dòng theo thứ tự tăng dần (theo bảng chữ cái). Sự khác biệt tinh tế giữa
SortKey.NFLvàSortKey.STDNAMElà tên tiêu chuẩn là một loại tên được in, có nghĩa là số dòng nhúng được so sánh theo một cách kỳ lạ. Ví dụ: các dòng 3, 20 và 40 (nếu tên tệp giống nhau) sẽ xuất hiện theo thứ tự chuỗi 20, 3 và 40. Ngược lại,SortKey.NFLthực hiện so sánh số của các số dòng. Trên thực tế,sort_stats(SortKey.NFL)cũng giống nhưsort_stats(SortKey.NAME, SortKey.FILENAME, SortKey.LINE).Vì lý do tương thích ngược, các đối số số
-1,0,1và2được cho phép. Chúng được hiểu lần lượt là'stdname','calls','time'và'cumulative'. Nếu định dạng kiểu cũ (số) này được sử dụng thì chỉ có một khóa sắp xếp (phím số) sẽ được sử dụng và các đối số bổ sung sẽ bị bỏ qua trong âm thầm.Added in version 3.7: Đã thêm enum SortKey.
- reverse_order()¶
Phương thức này dành cho lớp
Statsđảo ngược thứ tự của danh sách cơ bản trong đối tượng. Lưu ý rằng theo mặc định, thứ tự tăng dần và giảm dần được chọn chính xác dựa trên khóa sắp xếp được chọn.
- print_stats(*restrictions)¶
Phương thức này dành cho lớp
Statsin ra một báo cáo như được mô tả trong định nghĩaprofile.run().Thứ tự in dựa trên thao tác
sort_stats()cuối cùng được thực hiện trên đối tượng (có thể lưu ý trongadd()vàstrip_dirs()).Các đối số được cung cấp (nếu có) có thể được sử dụng để giới hạn danh sách ở các mục quan trọng. Ban đầu, danh sách được coi là tập hợp đầy đủ các chức năng được định hình. Mỗi hạn chế là một số nguyên (để chọn số dòng) hoặc một phân số thập phân nằm trong khoảng từ 0,0 đến 1,0 (để chọn phần trăm dòng) hoặc một chuỗi sẽ được hiểu là biểu thức chính quy (để khớp mẫu với tên tiêu chuẩn được in). Nếu một số hạn chế được đưa ra thì chúng sẽ được áp dụng tuần tự. Ví dụ:
print_stats(.1, 'foo:')
trước tiên sẽ giới hạn việc in ở 10% đầu tiên của danh sách và sau đó chỉ in các chức năng là một phần của tên tệp
.*foo:. Ngược lại, lệnh:print_stats('foo:', .1)
sẽ giới hạn danh sách ở tất cả các hàm có tên tệp
.*foo:và sau đó tiến hành chỉ in 10% đầu tiên trong số chúng.
- print_callers(*restrictions)¶
Phương thức này dành cho lớp
Statsin danh sách tất cả các hàm gọi từng hàm trong cơ sở dữ liệu được định hình. Thứ tự giống hệt với thứ tự được cung cấp bởiprint_stats()và định nghĩa của đối số hạn chế cũng giống hệt nhau. Mỗi người gọi được báo cáo trên dòng riêng của mình. Định dạng hơi khác một chút tùy thuộc vào trình lược tả tạo ra số liệu thống kê:Với
profile, một số được hiển thị trong ngoặc đơn sau mỗi người gọi để hiển thị số lần cuộc gọi cụ thể này được thực hiện. Để thuận tiện, số thứ hai không có dấu ngoặc đơn sẽ lặp lại thời gian tích lũy dành cho hàm ở bên phải.Với
cProfile, trước mỗi người gọi là ba số: số lần cuộc gọi cụ thể này được thực hiện cũng như tổng thời gian và thời gian tích lũy dành cho hàm hiện tại trong khi người gọi cụ thể này gọi nó.
- print_callees(*restrictions)¶
Phương thức này dành cho lớp
Statsin danh sách tất cả các hàm được gọi bởi hàm được chỉ định. Ngoài sự đảo ngược hướng gọi này (re: được gọi và được gọi bởi), các đối số và thứ tự giống hệt với phương thứcprint_callers().
- get_stats_profile()¶
Phương thức này trả về một phiên bản của StatsProfile, chứa ánh xạ tên hàm tới các phiên bản của FunctionProfile. Mỗi phiên bản FunctionProfile chứa thông tin liên quan đến hồ sơ của hàm, chẳng hạn như hàm chạy trong bao lâu, số lần nó được gọi, v.v...
Added in version 3.9: Đã thêm các lớp dữ liệu sau: StatsProfile, FunctionProfile. Đã thêm chức năng sau: get_stats_profile.
Hồ sơ xác định là gì?¶
Deterministic profiling nhằm phản ánh thực tế rằng tất cả các sự kiện function call, function return và exception đều được theo dõi và thời gian chính xác được thực hiện cho các khoảng thời gian giữa các sự kiện này (trong thời gian mã của người dùng đang thực thi). Ngược lại, statistical profiling (điều này không được mô-đun này thực hiện) lấy mẫu ngẫu nhiên con trỏ lệnh hiệu quả và suy ra thời gian đang được sử dụng ở đâu. Kỹ thuật thứ hai theo truyền thống đòi hỏi ít chi phí hơn (vì mã không cần phải được đo lường), nhưng chỉ cung cấp các dấu hiệu tương đối về thời gian được sử dụng.
Trong Python, vì có một trình thông dịch hoạt động trong quá trình thực thi nên không cần phải có mã công cụ để thực hiện lập hồ sơ xác định. Python tự động cung cấp hook (gọi lại tùy chọn) cho mỗi sự kiện. Ngoài ra, bản chất diễn giải của Python có xu hướng tăng thêm rất nhiều chi phí thực thi, nên việc lập hồ sơ xác định có xu hướng chỉ thêm chi phí xử lý nhỏ trong các ứng dụng điển hình. Kết quả là việc lập hồ sơ xác định không quá tốn kém nhưng vẫn cung cấp số liệu thống kê về thời gian chạy rộng rãi về việc thực thi chương trình Python.
Thống kê số lượng cuộc gọi có thể được sử dụng để xác định lỗi trong mã (số lượng đáng ngạc nhiên) và để xác định các điểm mở rộng nội tuyến có thể có (số lượng cuộc gọi cao). Thống kê thời gian nội bộ có thể được sử dụng để xác định "vòng lặp nóng" cần được tối ưu hóa cẩn thận. Thống kê thời gian tích lũy nên được sử dụng để xác định các lỗi cấp cao trong việc lựa chọn thuật toán. Lưu ý rằng việc xử lý bất thường về thời gian tích lũy trong trình lược tả này cho phép số liệu thống kê về việc triển khai thuật toán đệ quy được so sánh trực tiếp với việc triển khai lặp lại.
Hạn chế¶
Một hạn chế liên quan đến độ chính xác của thông tin thời gian. Có một vấn đề cơ bản với các trình lập hồ sơ xác định liên quan đến độ chính xác. Hạn chế rõ ràng nhất là "đồng hồ" cơ bản chỉ tích tắc với tốc độ (thường) khoảng 0,001 giây. Do đó, không có phép đo nào chính xác hơn đồng hồ cơ bản. Nếu thực hiện đủ số đo thì "lỗi" sẽ có xu hướng lấy giá trị trung bình. Thật không may, việc loại bỏ lỗi đầu tiên này sẽ gây ra nguồn lỗi thứ hai.
Vấn đề thứ hai là "mất một khoảng thời gian" từ khi một sự kiện được gửi đi cho đến khi có lệnh gọi của trình lược tả để có được thời gian thực sự là gets trạng thái của đồng hồ. Tương tự, có một độ trễ nhất định khi thoát khỏi trình xử lý sự kiện của trình lược tả kể từ thời điểm nhận được giá trị của đồng hồ (và sau đó bị loại bỏ), cho đến khi mã của người dùng được thực thi lại một lần nữa. Do đó, các hàm được gọi nhiều lần hoặc gọi nhiều hàm thường sẽ tích lũy lỗi này. Lỗi tích lũy theo kiểu này thường thấp hơn độ chính xác của đồng hồ (ít hơn một tích tắc đồng hồ), nhưng can sẽ tích lũy và trở nên rất đáng kể.
Vấn đề với profile quan trọng hơn so với cProfile có chi phí thấp hơn. Vì lý do này, profile cung cấp một phương tiện tự hiệu chỉnh cho một nền tảng nhất định để lỗi này có thể được loại bỏ theo xác suất (trung bình). Sau khi trình hồ sơ được hiệu chỉnh, nó sẽ chính xác hơn (theo nghĩa bình phương tối thiểu), nhưng đôi khi nó sẽ tạo ra các số âm (khi số lượng cuộc gọi cực kỳ thấp và các vị thần xác suất đang chống lại bạn :-). ) not có bị cảnh báo bởi những con số âm trong hồ sơ không. Chúng sẽ xuất hiện only nếu bạn đã hiệu chỉnh trình hồ sơ của mình và kết quả thực sự tốt hơn so với việc không hiệu chỉnh.
Hiệu chuẩn¶
Trình phân tích hồ sơ của mô-đun profile sẽ trừ một hằng số từ mỗi thời gian xử lý sự kiện để bù đắp chi phí cho việc gọi hàm thời gian và loại bỏ kết quả. Theo mặc định, hằng số là 0. Bạn có thể sử dụng quy trình sau để có được hằng số tốt hơn cho một nền tảng nhất định (xem Hạn chế).
hồ sơ nhập khẩu
pr = profile.Profile()
cho tôi trong phạm vi (5):
print(pr.calibrate(10000))
Phương thức này thực thi số lượng lệnh gọi Python do đối số đưa ra, trực tiếp và lặp lại trong trình lược tả, đo thời gian cho cả hai. Sau đó, nó tính toán chi phí ẩn cho mỗi sự kiện của trình lược tả và trả về chi phí đó dưới dạng float. Ví dụ: trên Intel Core i5 1,8 GHz chạy macOS và sử dụng time.process_time() của Python làm bộ hẹn giờ, con số kỳ diệu là khoảng 4,04e-6.
Mục tiêu của bài tập này là để có được một kết quả khá nhất quán. Nếu máy tính của bạn chạy nhanh very hoặc chức năng hẹn giờ của bạn có độ phân giải kém, bạn có thể phải vượt qua 100000 hoặc thậm chí 1000000 để có được kết quả nhất quán.
Khi bạn có câu trả lời nhất quán, bạn có thể sử dụng câu trả lời đó theo ba cách:
hồ sơ nhập khẩu
# 1. Áp dụng độ lệch được tính toán cho tất cả các phiên bản Hồ sơ được tạo sau đây.
profile.Profile.bias = your_computed_bias
# 2. Áp dụng độ lệch được tính toán cho một phiên bản Hồ sơ cụ thể.
pr = profile.Profile()
pr.bias = your_computed_bias
# 3. Chỉ định độ lệch được tính toán trong hàm tạo cá thể.
pr = profile.Profile(bias=your_computed_bias)
Nếu bạn có quyền lựa chọn, tốt hơn hết bạn nên chọn một hằng số nhỏ hơn và khi đó kết quả của bạn sẽ "ít thường xuyên hơn" hiển thị dưới dạng âm trong thống kê hồ sơ.
Sử dụng bộ hẹn giờ tùy chỉnh¶
Nếu bạn muốn thay đổi cách xác định thời gian hiện tại (ví dụ: để buộc sử dụng thời gian trên đồng hồ treo tường hoặc thời gian xử lý đã trôi qua), hãy chuyển hàm định giờ bạn muốn cho hàm tạo của lớp Profile:
pr = profile.Profile(your_time_func)
Trình lược tả kết quả sau đó sẽ gọi your_time_func. Tùy thuộc vào việc bạn đang sử dụng profile.Profile hay cProfile.Profile, giá trị trả về của your_time_func sẽ được diễn giải khác nhau:
profile.Profileyour_time_funcsẽ trả về một số hoặc một danh sách các số có tổng là thời gian hiện tại (như kết quả màos.times()trả về). Nếu hàm trả về một số thời gian duy nhất hoặc danh sách các số được trả về có độ dài bằng 2 thì bạn sẽ nhận được một phiên bản đặc biệt nhanh của quy trình gửi đi.Được cảnh báo rằng bạn nên hiệu chỉnh lớp trình lược tả cho chức năng hẹn giờ mà bạn chọn (xem Hiệu chuẩn). Đối với hầu hết các máy, bộ hẹn giờ trả về một giá trị số nguyên duy nhất sẽ mang lại kết quả tốt nhất về mặt chi phí thấp trong quá trình lập hồ sơ. (
os.times()là pretty không tốt vì nó trả về một bộ giá trị dấu phẩy động). Nếu bạn muốn thay thế một bộ hẹn giờ tốt hơn theo cách rõ ràng nhất, hãy lấy một lớp và thiết lập một phương thức điều phối thay thế để xử lý tốt nhất lệnh gọi bộ hẹn giờ của bạn, cùng với hằng số hiệu chuẩn thích hợp.cProfile.Profileyour_time_funcsẽ trả về một số duy nhất. Nếu nó trả về số nguyên, bạn cũng có thể gọi hàm tạo của lớp với đối số thứ hai chỉ định khoảng thời gian thực của một đơn vị thời gian. Ví dụ: nếuyour_integer_time_functrả về thời gian được đo bằng hàng nghìn giây, bạn sẽ xây dựng phiên bảnProfilenhư sau:pr = cProfile.Profile(your_integer_time_func, 0,001)
Vì lớp
cProfile.Profilekhông thể hiệu chỉnh được nên các chức năng hẹn giờ tùy chỉnh phải được sử dụng cẩn thận và phải nhanh nhất có thể. Để có kết quả tốt nhất với bộ hẹn giờ tùy chỉnh, có thể cần phải mã hóa cứng bộ hẹn giờ đó trong nguồn C của mô-đun_lsprofbên trong.
Python 3.3 bổ sung một số hàm mới trong time có thể được sử dụng để thực hiện các phép đo chính xác về quy trình hoặc thời gian trên đồng hồ treo tường. Ví dụ: xem time.perf_counter().