โครงการออยเลอร์และการแข่งขันการเข้ารหัสอื่น ๆ มักจะมีเวลาสูงสุดในการรัน กับงูหลามบางครั้งแนวทางที่ค่อนข้างค่อนข้างแออัดเกินไป - __main__
คือการเพิ่มรหัสระยะเวลาที่จะ
วิธีที่ดีในการทำโพรไฟล์ว่าโปรแกรม Python ใช้เวลานานแค่ไหน?
โครงการออยเลอร์และการแข่งขันการเข้ารหัสอื่น ๆ มักจะมีเวลาสูงสุดในการรัน กับงูหลามบางครั้งแนวทางที่ค่อนข้างค่อนข้างแออัดเกินไป - __main__
คือการเพิ่มรหัสระยะเวลาที่จะ
วิธีที่ดีในการทำโพรไฟล์ว่าโปรแกรม Python ใช้เวลานานแค่ไหน?
คำตอบ:
งูหลามรวมถึง Profiler ที่เรียกว่าcProfile ไม่เพียงให้เวลาการทำงานโดยรวมเท่านั้น แต่ยังแยกเวลาแต่ละฟังก์ชั่นแยกต่างหากและบอกให้คุณทราบว่ามีการเรียกใช้ฟังก์ชันแต่ละครั้งกี่ครั้งทำให้ง่ายต่อการพิจารณาว่าคุณควรทำการปรับแต่งที่ไหน
คุณสามารถโทรจากภายในรหัสของคุณหรือจากล่ามเช่นนี้
import cProfile
cProfile.run('foo()')
มีประโยชน์มากขึ้นคุณสามารถเรียกใช้ cProfile เมื่อเรียกใช้สคริปต์:
python -m cProfile myscript.py
เพื่อให้ง่ายยิ่งขึ้นฉันได้สร้างไฟล์แบตช์เล็ก ๆ ชื่อว่า 'profile.bat':
python -m cProfile %1
ดังนั้นสิ่งที่ฉันต้องทำคือเรียกใช้:
profile euler048.py
และฉันได้รับสิ่งนี้:
1007 function calls in 0.061 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.061 0.061 <string>:1(<module>)
1000 0.051 0.000 0.051 0.000 euler048.py:2(<lambda>)
1 0.005 0.005 0.061 0.061 euler048.py:2(<module>)
1 0.000 0.000 0.061 0.061 {execfile}
1 0.002 0.002 0.053 0.053 {map}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler objects}
1 0.000 0.000 0.000 0.000 {range}
1 0.003 0.003 0.003 0.003 {sum}
แก้ไข: Updated เชื่อมโยงไปยังแหล่งข้อมูลที่ดีจากวิดีโอ PyCon 2013 หัวข้อ
หลาม Profiling
นอกจากนี้ยังผ่าน YouTube
python -m cProfile -o <out.profile> <script>
) RunSnakeRun ที่เรียกใช้ตามที่runsnake <out.profile>
ประเมินค่าไม่ได้
cprofile
จะแนะนำยังคงprofile
มากกว่า
เมื่อก่อนฉันทำ pycallgraph
สร้างภาพเสมือนจริงจากรหัสไพ ธ อนของคุณ แก้ไข:ฉันได้อัปเดตตัวอย่างเพื่อทำงานกับ 3.3 ซึ่งเป็นรุ่นล่าสุดของการเขียนนี้
หลังจากpip install pycallgraph
และติดตั้ง GraphVizคุณสามารถเรียกใช้จากบรรทัดคำสั่ง:
pycallgraph graphviz -- ./mypythonscript.py
หรือคุณสามารถโปรไฟล์บางส่วนของรหัสของคุณ:
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
with PyCallGraph(output=GraphvizOutput()):
code_to_profile()
สิ่งเหล่านี้จะสร้างpycallgraph.png
ไฟล์คล้ายกับภาพด้านล่าง:
Traceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
sudo apt-get install graphviz
นี้เป็นเพียง
เป็นค่าที่ชี้ให้เห็นว่าการใช้ตัวสร้างโปรไฟล์ใช้งานได้ (โดยค่าเริ่มต้น) บนเธรดหลักและคุณจะไม่ได้รับข้อมูลใด ๆ จากเธรดอื่น ๆ หากคุณใช้พวกเขา นี้อาจจะเป็นบิตของ gotcha ที่มันจะสมบูรณ์ไม่ได้กล่าวถึงในเอกสาร Profiler
หากคุณต้องการโพรไฟล์เธรดคุณจะต้องดูthreading.setprofile()
ฟังก์ชันในเอกสารด้วย
คุณสามารถสร้างthreading.Thread
คลาสย่อยของคุณเองเพื่อทำ:
class ProfiledThread(threading.Thread):
# Overrides threading.Thread.run()
def run(self):
profiler = cProfile.Profile()
try:
return profiler.runcall(threading.Thread.run, self)
finally:
profiler.dump_stats('myprofile-%d.profile' % (self.ident,))
และใช้ProfiledThread
คลาสนั้นแทนคลาสมาตรฐาน มันอาจให้ความยืดหยุ่นแก่คุณมากกว่า แต่ฉันไม่แน่ใจว่ามันคุ้มค่าโดยเฉพาะถ้าคุณใช้รหัสบุคคลที่สามซึ่งไม่ใช้คลาสของคุณ
target
ฟังก์ชั่นของเธรดซึ่งเป็นสิ่งที่การthreading.Thread.run()
เรียกใช้งาน แต่ที่ผมกล่าวในคำตอบก็อาจจะไม่คุ้มค่าที่จะ subclass กระทู้ตั้งแต่รหัสของบุคคลที่สามใด ๆ threading.setprofile()
ที่จะได้ใช้มันและเพื่อใช้แทน
python wiki เป็นหน้าที่ยอดเยี่ยมสำหรับการทำโปรไฟล์ทรัพยากร: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code
เช่นเดียวกับเอกสารหลาม: http://docs.python.org/library/profile.html
ดังที่แสดงโดย Chris Lawlor cProfile เป็นเครื่องมือที่ยอดเยี่ยมและสามารถใช้พิมพ์บนหน้าจอได้อย่างง่ายดาย:
python -m cProfile -s time mine.py <args>
หรือไปยังไฟล์:
python -m cProfile -o output.file mine.py <args>
PS> ถ้าคุณใช้ Ubuntu ตรวจสอบให้แน่ใจว่าได้ติดตั้ง python-profile แล้ว
apt-get install python-profiler
หากคุณส่งออกไปยังไฟล์คุณจะได้รับการสร้างภาพที่ดีโดยใช้เครื่องมือดังต่อไปนี้
PyCallGraph: เครื่องมือในการสร้างภาพกราฟการโทร
ติดตั้ง:
pip install pycallgraph
วิ่ง:
pycallgraph mine.py args
ดู:
gimp pycallgraph.png
คุณสามารถใช้สิ่งที่คุณต้องการดูไฟล์ png ฉันใช้ gimp
น่าเสียดายที่ฉันมักจะได้รับ
dot: กราฟมีขนาดใหญ่เกินไปสำหรับบิตแมป cairo-renderer ปรับสเกลโดย 0.257079 ให้เหมาะสม
ซึ่งทำให้ภาพของฉันเล็กผิดปกติ ดังนั้นฉันมักจะสร้างไฟล์ svg:
pycallgraph -f svg -o pycallgraph.svg mine.py <args>
PS> ตรวจสอบให้แน่ใจว่าได้ติดตั้ง graphviz (ซึ่งมีโปรแกรม dot):
pip install graphviz
กราฟทางเลือกโดยใช้ gprof2dot ผ่าน @maxy / @quodlibetor:
pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
@ ความคิดเห็นของ Maxy ในคำตอบนี้ช่วยฉันได้มากพอที่ฉันคิดว่ามันสมควรคำตอบของตัวเอง: ฉันมีไฟล์. pstats ที่สร้างโดย cProfile แล้วและฉันไม่ต้องการเรียกใช้ pycallgraph อีกครั้งดังนั้นฉันจึงใช้gprof2dotและสวยมาก svgs:
$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg
และ BLAM!
มันใช้จุด (เช่นเดียวกับที่ pycallgraph ใช้) ดังนั้นเอาต์พุตจะคล้ายกัน ฉันได้รับความประทับใจที่ gprof2dot แพ้ข้อมูลน้อยลง:
pwd
/gprof2dot/gprof2dot.py $ HOME / bin (หรือใช้ ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin ในเชลล์ส่วนใหญ่ - การเน้นเสียงหนักหนาสาหัสนั้นถูกจัดรูปแบบในครั้งแรก รุ่น)
ln
รับคำสั่งโต้แย้งผิดเกือบทุกครั้ง
ฉันพบเครื่องมือที่มีประโยชน์ชื่อSnakeVizเมื่อค้นคว้าหัวข้อนี้ SnakeViz เป็นเครื่องมือสร้างภาพโปรไฟล์บนเว็บ มันง่ายมากที่จะติดตั้งและใช้งาน วิธีปกติที่ฉันใช้คือสร้างไฟล์สถิติด้วย%prun
แล้วทำการวิเคราะห์ใน SnakeViz
เทคนิคหลัก ได้แก่ ใช้แผนภูมิ Sunburstดังแสดงด้านล่างซึ่งลำดับชั้นของการเรียกใช้ฟังก์ชันถูกจัดเรียงเป็นเลเยอร์ของส่วนโค้งและข้อมูลเวลาที่เข้ารหัสในความกว้างเชิงมุม
สิ่งที่ดีที่สุดคือคุณสามารถโต้ตอบกับแผนภูมิ ตัวอย่างเช่นหากต้องการขยายเข้าไปหนึ่งสามารถคลิกที่ส่วนโค้งและส่วนโค้งและลูกหลานของมันจะถูกขยายเป็นซ่านใหม่เพื่อแสดงรายละเอียดเพิ่มเติม
วิธีที่ง่ายและรวดเร็วที่สุดในการค้นหาว่าจะไปที่ไหนตลอดเวลา
1. pip install snakeviz
2. python -m cProfile -o temp.dat <PROGRAM>.py
3. snakeviz temp.dat
วาดแผนภูมิวงกลมในเบราว์เซอร์ ชิ้นที่ใหญ่ที่สุดคือฟังก์ชันที่มีปัญหา ง่ายมาก.
ฉันคิดว่าcProfile
มันยอดเยี่ยมสำหรับการทำโปรไฟล์ในขณะที่kcachegrind
ดีสำหรับการมองเห็นผลลัพธ์ pyprof2calltree
ในระหว่างที่จับแปลงไฟล์
python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
ในการติดตั้งเครื่องมือที่จำเป็น (บน Ubuntu อย่างน้อย):
apt-get install kcachegrind
pip install pyprof2calltree
ผลลัพธ์:
brew install qcachegrind
และ substitude แต่ละkcachegrind
ที่มีqcachegrind
ในรายละเอียดสำหรับโปรไฟล์ที่ประสบความสำเร็จ
export QT_X11_NO_MITSHM=1
นอกจากนี้มูลค่าการกล่าวขวัญก็คือตัวดูการถ่ายโอนข้อมูล GUI cProfile RunSnakeRun RunSnakeRunช่วยให้คุณสามารถจัดเรียงและเลือกได้จึงซูมเข้าในส่วนที่เกี่ยวข้องของโปรแกรม ขนาดของรูปสี่เหลี่ยมผืนผ้าในภาพเป็นสัดส่วนกับเวลาที่ถ่าย หากคุณวางเมาส์เหนือสี่เหลี่ยมมันจะไฮไลต์การโทรเข้าในตารางและทุกที่บนแผนที่ เมื่อคุณคลิกสองครั้งที่สี่เหลี่ยมมันจะซูมเข้าที่ส่วนนั้น มันจะแสดงให้คุณเห็นว่าใครเรียกส่วนนั้นและส่วนนั้นเรียกว่าอะไร
ข้อมูลเชิงอธิบายมีประโยชน์มาก มันแสดงรหัสสำหรับบิตนั้นซึ่งจะมีประโยชน์เมื่อคุณจัดการกับการเรียกใช้ไลบรารีในตัว มันบอกคุณว่าไฟล์และบรรทัดอะไรในการค้นหารหัส
ต้องการชี้ให้เห็นว่า OP พูดว่า 'ทำโปรไฟล์' แต่ดูเหมือนว่าเขาหมายถึง 'เวลา' โปรดทราบว่าโปรแกรมจะทำงานช้าลงเมื่อทำโปรไฟล์
โมดูลการทำโปรไฟล์ที่ดีคือ line_profiler (เรียกว่าการใช้สคริปต์ kernprof.py) ก็สามารถดาวน์โหลดได้ที่นี่
ความเข้าใจของฉันคือ cProfile ให้ข้อมูลเกี่ยวกับเวลาทั้งหมดที่ใช้ในแต่ละฟังก์ชันเท่านั้น ดังนั้นแต่ละบรรทัดของรหัสจะไม่หมดเวลา นี่เป็นปัญหาในการคำนวณทางวิทยาศาสตร์เนื่องจากบ่อยครั้งที่หนึ่งบรรทัดอาจใช้เวลานาน อย่างที่ฉันจำได้ cProfile ไม่ได้ใช้เวลาในการพูด numpy.dot
ฉันเพิ่งสร้างปลาทูน่าเพื่อให้เห็นภาพของ Python runtime และนำเข้าโปรไฟล์; สิ่งนี้อาจมีประโยชน์ที่นี่
ติดตั้งด้วย
pip install tuna
สร้างโปรไฟล์รันไทม์
python3 -m cProfile -o program.prof yourfile.py
หรือโปรไฟล์นำเข้า (จำเป็นต้องมี Python 3.7+)
python3 -X importprofile yourfile.py 2> import.log
จากนั้นก็เรียกใช้ปลาทูน่าในไฟล์
tuna program.prof
line_profiler
(นำเสนอแล้วที่นี่) ยังได้รับแรงบันดาลใจ pprofile
ซึ่งอธิบายว่า:
Line-granularity ตัวกำหนดเธรดและตัวกำหนด pure-python
มันมี line-granularity เนื่องจากline_profiler
เป็น Python แท้สามารถใช้เป็นคำสั่งแบบสแตนด์อโลนหรือโมดูลและยังสามารถสร้างไฟล์รูปแบบ callgrind ที่สามารถวิเคราะห์ได้อย่างง่ายดายด้วย[k|q]cachegrind
รูปแบบที่สามารถวิเคราะห์ได้อย่างง่ายดายด้วย
นอกจากนี้ยังมีvprofซึ่งเป็นแพ็คเกจ Python ที่อธิบายดังนี้:
[... ] ให้การแสดงข้อมูลแบบอินเทอร์แอคทีฟและอินเทอร์แอคทีฟสำหรับคุณลักษณะของโปรแกรม Python เช่นเวลาทำงานและการใช้หน่วยความจำ
มีคำตอบที่ดีมากมาย แต่พวกเขาอาจใช้บรรทัดคำสั่งหรือโปรแกรมภายนอกบางโปรแกรมสำหรับการทำโปรไฟล์และ / หรือเรียงลำดับผลลัพธ์
ฉันพลาดวิธีที่ฉันสามารถใช้ใน IDE ของฉัน (eclipse-PyDev) โดยไม่ต้องแตะที่บรรทัดคำสั่งหรือติดตั้งอะไร ดังนั้นนี่คือ
def count():
from math import sqrt
for x in range(10**5):
sqrt(x)
if __name__ == '__main__':
import cProfile, pstats
cProfile.run("count()", "{}.profile".format(__file__))
s = pstats.Stats("{}.profile".format(__file__))
s.strip_dirs()
s.sort_stats("time").print_stats(10)
ดูเอกสารหรือคำตอบอื่น ๆ สำหรับข้อมูลเพิ่มเติม
การปฏิบัติตามคำตอบของโจวชอว์เกี่ยวกับรหัสแบบมัลติเธรดไม่ทำงานตามที่คาดไว้ฉันคิดว่าruncall
วิธีการใน cProfile เป็นเพียงการทำself.enable()
และself.disable()
โทรไปรอบ ๆ การเรียกใช้ฟังก์ชันที่ทำโปรไฟล์ดังนั้นคุณสามารถทำได้เองและมีรหัสที่คุณต้องการ รบกวนน้อยที่สุดด้วยรหัสที่มีอยู่
cprofile.py
รหัสที่มา 's เผยให้เห็นว่าเป็นว่าสิ่งที่runcall()
ทำ มีความเฉพาะเจาะจงมากขึ้นหลังจากสร้างอินสแตนซ์โปรไฟล์ด้วยprof = cprofile.Profile()
โทรทันทีprof.disable()
แล้วเพิ่มprof.enable()
และprof.disable()
โทรไปยังส่วนของรหัสที่คุณต้องการทำโปรไฟล์
ในแหล่งที่มาของ Virtaal มีคลาสที่มีประโยชน์มากและมัณฑนากรที่สามารถสร้างโปรไฟล์ (แม้สำหรับวิธีการ / ฟังก์ชั่นที่เฉพาะเจาะจง) นั้นง่ายมาก ผลลัพธ์นั้นสามารถดูได้อย่างสะดวกสบายใน KCacheGrind
cProfile นั้นยอดเยี่ยมสำหรับการทำโปรไฟล์อย่างรวดเร็ว แต่ส่วนใหญ่แล้วมันก็สิ้นสุดลงสำหรับฉันด้วยข้อผิดพลาด Function runctx แก้ปัญหานี้โดยการเริ่มต้นอย่างถูกต้องกับสภาพแวดล้อมและตัวแปรหวังว่ามันจะมีประโยชน์สำหรับใครบางคน:
import cProfile
cProfile.runctx('foo()', None, locals())
หากคุณต้องการทำ profiler สะสมหมายถึงการเรียกใช้ฟังก์ชันหลายครั้งในแถวและดูผลรวมของผลลัพธ์
คุณสามารถใช้สิ่งนี้ cumulative_profiler
มัณฑนากร :
เป็น python> = 3.6 เฉพาะ แต่คุณสามารถลบออกnonlocal
เพื่อใช้กับเวอร์ชันเก่ากว่าได้
import cProfile, pstats
class _ProfileFunc:
def __init__(self, func, sort_stats_by):
self.func = func
self.profile_runs = []
self.sort_stats_by = sort_stats_by
def __call__(self, *args, **kwargs):
pr = cProfile.Profile()
pr.enable() # this is the profiling section
retval = self.func(*args, **kwargs)
pr.disable()
self.profile_runs.append(pr)
ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
return retval, ps
def cumulative_profiler(amount_of_times, sort_stats_by='time'):
def real_decorator(function):
def wrapper(*args, **kwargs):
nonlocal function, amount_of_times, sort_stats_by # for python 2.x remove this row
profiled_func = _ProfileFunc(function, sort_stats_by)
for i in range(amount_of_times):
retval, ps = profiled_func(*args, **kwargs)
ps.print_stats()
return retval # returns the results of the function
return wrapper
if callable(amount_of_times): # incase you don't want to specify the amount of times
func = amount_of_times # amount_of_times is the function in here
amount_of_times = 5 # the default amount
return real_decorator(func)
return real_decorator
ตัวอย่าง
การทำโปรไฟล์ฟังก์ชัน baz
import time
@cumulative_profiler
def baz():
time.sleep(1)
time.sleep(2)
return 1
baz()
baz
วิ่ง 5 ครั้งและพิมพ์สิ่งนี้:
20 function calls in 15.003 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
10 15.003 1.500 15.003 1.500 {built-in method time.sleep}
5 0.000 0.000 15.003 3.001 <ipython-input-9-c89afe010372>:3(baz)
5 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
การระบุจำนวนครั้ง
@cumulative_profiler(3)
def baz():
...
โซลูชันเทอร์มินัลเท่านั้น (และง่ายที่สุด) ในกรณีที่ UI แฟนซีทั้งหมดเหล่านั้นล้มเหลวในการติดตั้งหรือเรียกใช้:
ละเว้นcProfile
ทั้งหมดและแทนที่ด้วยpyinstrument
ที่จะรวบรวมและแสดงแผนผังการโทรทันทีหลังจากดำเนินการ
ติดตั้ง:
$ pip install pyinstrument
โปรไฟล์และผลการแสดง:
$ python -m pyinstrument ./prog.py
ทำงานร่วมกับ python2 และ 3
[แก้ไข] เอกสารของ API ที่สำหรับ profiling เพียงส่วนหนึ่งของรหัสที่สามารถพบได้ที่นี่
วิธีของฉันคือการใช้ yappi ( https://github.com/sumerc/yappi ) มันมีประโยชน์อย่างยิ่งเมื่อรวมกับเซิร์ฟเวอร์ RPC ที่ (แม้แต่การดีบัก) คุณลงทะเบียนวิธีการเริ่มหยุดและพิมพ์ข้อมูลการทำโปรไฟล์เช่นด้วยวิธีนี้:
@staticmethod
def startProfiler():
yappi.start()
@staticmethod
def stopProfiler():
yappi.stop()
@staticmethod
def printProfiler():
stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
statPrint = '\n'
namesArr = [len(str(stat[0])) for stat in stats.func_stats]
log.debug("namesArr %s", str(namesArr))
maxNameLen = max(namesArr)
log.debug("maxNameLen: %s", maxNameLen)
for stat in stats.func_stats:
nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
log.debug('nameAppendSpaces: %s', nameAppendSpaces)
blankSpace = ''
for space in nameAppendSpaces:
blankSpace += space
log.debug("adding spaces: %s", len(nameAppendSpaces))
statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"
log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
log.log(1000, statPrint)
จากนั้นเมื่อโปรแกรมของคุณทำงานคุณสามารถเริ่มโปรแกรมสร้างโปรไฟล์ได้ตลอดเวลาโดยการเรียกใช้startProfiler
วิธี RPC และถ่ายโอนข้อมูลการทำโปรไฟล์ไปยังไฟล์บันทึกโดยการโทรprintProfiler
(หรือปรับเปลี่ยนวิธี rpc เพื่อส่งกลับไปยังผู้เรียก) และรับผลลัพธ์ดังกล่าว:
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
name ncall ttot tsub
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
C:\Python27\lib\sched.py.run:80 22 0.11 0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66 1 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243 4 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4 0.0 0.0
<string>.__new__:8 220 0.0 0.0
C:\Python27\lib\socket.py.close:276 4 0.0 0.0
C:\Python27\lib\threading.py.__init__:558 1 0.0 0.0
<string>.__new__:8 4 0.0 0.0
C:\Python27\lib\threading.py.notify:372 1 0.0 0.0
C:\Python27\lib\rfc822.py.getheader:285 4 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301 1 0.0 0.0
C:\Python27\lib\xmlrpclib.py.end:816 3 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467 1 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460 1 0.0 0.0
C:\Python27\lib\SocketServer.py.close_request:475 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066 4 0.0 0.0
มันอาจจะไม่เป็นประโยชน์สำหรับสคริปต์สั้น ๆ แต่ช่วยในการเพิ่มประสิทธิภาพกระบวนการประเภทเซิร์ฟเวอร์โดยเฉพาะอย่างยิ่งเมื่อprintProfiler
วิธีการที่สามารถเรียกหลายครั้งในช่วงเวลาเพื่อโปรไฟล์และเปรียบเทียบเช่นสถานการณ์การใช้งานโปรแกรมที่แตกต่างกัน
ใน yappi รุ่นที่ใหม่กว่ารหัสต่อไปนี้จะใช้งานได้:
@staticmethod
def printProfile():
yappi.get_func_stats().print_all()
def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)})
(ตกลงหลังจากพยายามสองครั้งเพื่อใส่รหัสบล็อกลงในความคิดเห็นที่ฉันยอมแพ้นี่เป็นเรื่องยากสำหรับเว็บไซต์ถามตอบ )
เครื่องมือใหม่ในการจัดการการทำโปรไฟล์ใน Python คือ PyVmMonitor: http://www.pyvmmonitor.com/
มันมีคุณสมบัติพิเศษบางอย่างเช่น
หมายเหตุ: มันเป็นโฆษณา แต่ฟรีสำหรับโอเพนซอร์ส
gprof2dot_magic
ฟังก์ชั่นเวทย์มนตร์สำหรับgprof2dot
โพรไฟล์คำสั่ง Python ใด ๆ เป็นกราฟ DOT ใน JupyterLab หรือ Jupyter Notebook
GitHub repo: https://github.com/mattijn/gprof2dot_magic
การติดตั้ง
gprof2dot_magic
ให้แน่ใจว่าคุณได้แพคเกจหลาม
pip install gprof2dot_magic
มันอ้างอิงgprof2dot
และgraphviz
จะถูกติดตั้งเช่นกัน
การใช้
หากต้องการเปิดใช้งานฟังก์ชั่นเวทย์มนตร์แรกให้โหลดgprof2dot_magic
โมดูล
%load_ext gprof2dot_magic
จากนั้นโปรไฟล์รายการคำสั่งใด ๆ เป็นกราฟ DOT เช่น:
%gprof2dot print('hello world')
เคยต้องการที่จะรู้ว่าสิ่งที่สคริปต์หลามกำลังทำอะไร ป้อนเชลล์ตรวจสอบ Inspect Shell ให้คุณพิมพ์ / แก้ไขกลมและเรียกใช้ฟังก์ชั่นโดยไม่ขัดจังหวะสคริปต์ที่ทำงานอยู่ ขณะนี้มีประวัติการเติมคำสั่งอัตโนมัติ (เฉพาะบน linux)
Inspect Shell ไม่ใช่ดีบักเกอร์แบบ pdb
https://github.com/amoffat/Inspect-Shell
คุณสามารถใช้มัน (และนาฬิกาข้อมือของคุณ)
เพิ่มในhttps://stackoverflow.com/a/582337/1070617 ,
ฉันเขียนโมดูลนี้ที่ช่วยให้คุณใช้ cProfile และดูผลลัพธ์ได้อย่างง่ายดาย เพิ่มเติมได้ที่นี่: https://github.com/ymichael/cprofilev
$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.
โปรดดูเพิ่มเติมที่: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.htmlเกี่ยวกับวิธีการทำความเข้าใจสถิติที่เก็บรวบรวม
มันจะขึ้นอยู่กับสิ่งที่คุณต้องการดูจากโปรไฟล์ การวัดเวลาแบบง่ายสามารถทำได้โดย (ทุบตี)
time python python_prog.py
แม้แต่ '/ usr / bin / time' ก็สามารถแสดงผลตัวชี้วัดแบบละเอียดได้โดยใช้การตั้งค่าสถานะ '--verbose'
ในการตรวจสอบตัวชี้วัดเวลาที่กำหนดโดยแต่ละฟังก์ชั่นและเพื่อให้เข้าใจถึงจำนวนเวลาที่ใช้ไปกับฟังก์ชั่นได้ดีขึ้นคุณสามารถใช้ inPilt cProfile ใน python
การเข้าสู่ตัวชี้วัดที่มีรายละเอียดมากขึ้นเช่นประสิทธิภาพเวลาไม่ใช่ตัวชี้วัดเพียงอย่างเดียว คุณสามารถกังวลเกี่ยวกับหน่วยความจำเธรดและอื่น ๆ
ตัวเลือกการทำโปรไฟล์:
1. line_profilerเป็นอีกหนึ่ง profiler ที่ใช้กันโดยทั่วไปเพื่อค้นหาตัวชี้วัดเวลาแบบทีละบรรทัด
2. memory_profilerเป็นเครื่องมือในการใช้หน่วยความจำโปรไฟล์
3. heapy (จากโครงการ Guppy)โปรไฟล์วิธีใช้ออบเจ็กต์ในฮีป
เหล่านี้เป็นของทั่วไปที่ฉันมักจะใช้ แต่ถ้าคุณต้องการทราบข้อมูลเพิ่มเติมลองอ่านหนังสือเล่มนี้ มันเป็นหนังสือที่ค่อนข้างดีในการเริ่มต้นโดยคำนึงถึงประสิทธิภาพ คุณสามารถย้ายไปยังหัวข้อขั้นสูงเกี่ยวกับการใช้ Cython และ JIT (Just-in-time) เรียบเรียง
ด้วยโปรแกรมรวบรวมข้อมูลเชิงสถิติเช่นaustinไม่จำเป็นต้องใช้เครื่องมือหมายความว่าคุณสามารถดึงข้อมูลออกจากแอพพลิเคชั่น Python ได้ง่ายๆด้วย
austin python3 my_script.py
เอาท์พุทดิบไม่มีประโยชน์มาก แต่คุณสามารถไปป์ที่Flamegraph.pl เพื่อรับกราฟเปลวไฟแทนข้อมูลที่ให้การแบ่งเวลาที่ใช้ (วัดเป็นไมโครวินาทีของเรียลไทม์)
austin python3 my_script.py | flamegraph.pl > my_script_profile.svg
นอกจากนี้ยังมีผู้สร้างสถิติที่เรียกว่า statprof
ทางสถิติที่เรียกว่า มันเป็นเครื่องมือสร้างตัวอย่างเพื่อเพิ่มค่าใช้จ่ายน้อยที่สุดให้กับรหัสของคุณและให้การกำหนดเวลาแบบอิงบรรทัด (ไม่ใช่แค่ตามฟังก์ชั่น) เหมาะสำหรับแอปพลิเคชันแบบเรียลไทม์เช่นเกม แต่อาจมีความแม่นยำน้อยกว่า cProfile
รุ่นใน pypiเป็นบิตเก่าเพื่อให้สามารถติดตั้งได้ด้วยpip
โดยการระบุพื้นที่เก็บข้อมูลคอมไพล์ :
pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01
คุณสามารถเรียกใช้เช่นนี้:
import statprof
with statprof.profile():
my_questionable_function()
ดูสิ่งนี้ด้วย https://stackoverflow.com/a/10333592/320036
ฉันเพิ่งพัฒนาผู้สร้างโปรไฟล์ของตัวเองซึ่งได้รับแรงบันดาลใจจาก pypref_time:
https://github.com/modaresimr/auto_profiler
โดยการเพิ่มเครื่องมือตกแต่งมันจะแสดงแผนผังของฟังก์ชั่นที่ใช้เวลานาน
@Profiler(depth=4, on_disable=show)
Install by: pip install auto_profiler
import time # line number 1
import random
from auto_profiler import Profiler, Tree
def f1():
mysleep(.6+random.random())
def mysleep(t):
time.sleep(t)
def fact(i):
f1()
if(i==1):
return 1
return i*fact(i-1)
def show(p):
print('Time [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
'-----------------------------------------------------------------------')
print(Tree(p.root, threshold=0.5))
@Profiler(depth=4, on_disable=show)
def main():
for i in range(5):
f1()
fact(3)
if __name__ == '__main__':
main()
Time [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974] main [auto-profiler/profiler.py:267] [/test/t2.py:30]
├── 5.954s [5 * 1.191] f1 [/test/t2.py:34] [/test/t2.py:14]
│ └── 5.954s [5 * 1.191] mysleep [/test/t2.py:15] [/test/t2.py:17]
│ └── 5.954s [5 * 1.191] <time.sleep>
|
|
| # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020] fact [/test/t2.py:36] [/test/t2.py:20]
├── 0.849s [1 * 0.849] f1 [/test/t2.py:21] [/test/t2.py:14]
│ └── 0.849s [1 * 0.849] mysleep [/test/t2.py:15] [/test/t2.py:17]
│ └── 0.849s [1 * 0.849] <time.sleep>
└── 2.171s [1 * 2.171] fact [/test/t2.py:24] [/test/t2.py:20]
├── 1.552s [1 * 1.552] f1 [/test/t2.py:21] [/test/t2.py:14]
│ └── 1.552s [1 * 1.552] mysleep [/test/t2.py:15] [/test/t2.py:17]
└── 0.619s [1 * 0.619] fact [/test/t2.py:24] [/test/t2.py:20]
└── 0.619s [1 * 0.619] f1 [/test/t2.py:21] [/test/t2.py:14]
เมื่อฉันไม่รูทบนเซิร์ฟเวอร์ฉันใช้ lsprofcalltree.pyและเรียกใช้โปรแกรมเช่นนี้:
python lsprofcalltree.py -o callgrind.1 test.py
จากนั้นฉันสามารถเปิดรายงานด้วยซอฟต์แวร์ที่เข้ากันได้กับcallgrindเช่นqcachegrind
สำหรับการรับสถิติโพรไฟล์อย่างรวดเร็วสำหรับตัวอย่างโค้ดของคุณบนโน้ตบุ๊ก IPython หนึ่งสามารถฝัง line_profiler และ memory_profiler ลงในสมุดบันทึกของพวกเขาได้โดยตรง
!pip install line_profiler
!pip install memory_profiler
%load_ext line_profiler
%load_ext memory_profiler
%time print('Outputs CPU time,Wall Clock time')
#CPU times: user 2 µs, sys: 0 ns, total: 2 µs Wall time: 5.96 µs
ให้:
%timeit -r 7 -n 1000 print('Outputs execution time of the snippet')
#1000 loops, best of 7: 7.46 ns per loop
%prun -s cumulative 'Code to profile'
ให้:
%memit 'Code to profile'
#peak memory: 199.45 MiB, increment: 0.00 MiB
ให้:
#Example function
def fun():
for i in range(10):
print(i)
#Usage: %lprun <name_of_the_function> function
%lprun -f fun fun()
ให้: