أين يقضي نص بيثون الوقت الخاص بي؟ هل هناك "وقت مفقود" في تتبع cprofile / pstats الخاص بي؟
-
03-10-2019 - |
سؤال
أنا أحاول أن أتعامل مع نص Python طويل المدى. يقوم البرنامج النصي ببعض التحليل المكاني على مجموعة بيانات GIS النقطية باستخدام وحدة GDAL. يستخدم البرنامج النصي حاليًا ثلاثة ملفات ، وهو البرنامج النصي الرئيسي الذي يحلق على وحدات البكسل النقطية المسمى find_pixel_pairs.py
, ، ذاكرة التخزين المؤقت البسيطة في lrucache.py
وبعض فصول MASC في utils.py
. لقد قمت بتعيين الكود على مجموعة بيانات معتدلة الحجم. pstats
عائدات:
p.sort_stats('cumulative').print_stats(20)
Thu May 6 19:16:50 2010 phes.profile
355483738 function calls in 11644.421 CPU seconds
Ordered by: cumulative time
List reduced from 86 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.008 0.008 11644.421 11644.421 <string>:1(<module>)
1 11064.926 11064.926 11644.413 11644.413 find_pixel_pairs.py:49(phes)
340135349 544.143 0.000 572.481 0.000 utils.py:173(extent_iterator)
8831020 18.492 0.000 18.492 0.000 {range}
231922 3.414 0.000 8.128 0.000 utils.py:152(get_block_in_bands)
142739 1.303 0.000 4.173 0.000 utils.py:97(search_extent_rect)
745181 1.936 0.000 2.500 0.000 find_pixel_pairs.py:40(is_no_data)
285478 1.801 0.000 2.271 0.000 utils.py:98(intify)
231922 1.198 0.000 2.013 0.000 utils.py:116(block_to_pixel_extent)
695766 1.990 0.000 1.990 0.000 lrucache.py:42(get)
1213166 1.265 0.000 1.265 0.000 {min}
1031737 1.034 0.000 1.034 0.000 {isinstance}
142740 0.563 0.000 0.909 0.000 utils.py:122(find_block_extent)
463844 0.611 0.000 0.611 0.000 utils.py:112(block_to_pixel_coord)
745274 0.565 0.000 0.565 0.000 {method 'append' of 'list' objects}
285478 0.346 0.000 0.346 0.000 {max}
285480 0.346 0.000 0.346 0.000 utils.py:109(pixel_coord_to_block_coord)
324 0.002 0.000 0.188 0.001 utils.py:27(__init__)
324 0.016 0.000 0.186 0.001 gdal.py:848(ReadAsArray)
1 0.000 0.000 0.160 0.160 utils.py:50(__init__)
تحتوي المكالمتين الأعلى على الحلقة الرئيسية - التحليل بأكمله. مجموع المكالمات المتبقية إلى أقل من 625 من 11644 ثانية. أين تقضي الـ 11000 ثانية المتبقية؟ هل كل شيء داخل الحلقة الرئيسية find_pixel_pairs.py
؟ إذا كان الأمر كذلك ، هل يمكنني معرفة أسطر التعليمات البرمجية التي تستغرق معظم الوقت؟
المحلول
أنت محق في أن يقضي معظم الوقت في phes
الوظيفة على الخط 49 من find_pixel_pairs.py
. لمعرفة المزيد ، تحتاج إلى الانفصال phes
في المزيد من الوظائف الفرعية ، ثم reprofile.
نصائح أخرى
ننسى الوظائف والقياس. استخدم هذه التقنية. ما عليك سوى تشغيله في وضع التصحيح ، وقم بـ Ctrl-C عدة مرات. سيُظهر لك مكدس المكالمات بالضبط خطوط التعليمات البرمجية المسؤولة عن الوقت.
وأضاف: على سبيل المثال ، توقف 10 مرات. إذا ، كما يقول EOL ، يتم إنفاق 10400 ثانية من أصل 11000 phes
, ، ثم في حوالي 9 من هذه الإيقاف المؤقت ، سوف تتوقف هناك مباشرة. إذا ، من ناحية أخرى ، فإنها تقضي جزءًا كبيرًا من الوقت في بعض الروتين الفرعي يسمى من phes
, ، لن ترى فقط مكان وجوده في تلك الروتين الفرعي ، ولكن سترى الخطوط التي تسميها ، والتي هي أيضًا مسؤولة عن الوقت ، وما إلى ذلك ، أعلى مكدس الاتصال.
الوقت الذي يقضيه في تنفيذ الكود من كل وظيفة أو طريقة في tottime
عمودي. ال cumtime
الطريقة هي tottime
+الوقت الذي يقضيه في وظائف تسمى.
في قائمتك ، ترى أن الـ 11000 ثانية التي تبحث عنها تقضيها مباشرة من قبل phes
تعمل نفسها. ما يسميه يستغرق فقط حوالي 600 ثانية.
وبالتالي ، تريد أن تجد ما يستغرق وقتًا phes
, ، عن طريق تقسيمها إلى وظائف فرعية وإعادة توصيل ، كما اقترح unutbu.
إذا حددت إمكانية الاختناقات في phes
وظيفة/الطريقة في find_pixel_pairs.py
, ، يمكنك استخدام line_profiler
للحصول على أرقام أداء ملف تعريف تنفيذ خط واحد على حدة (تم نسخها من سؤال آخر هنا):
Timer unit: 1e-06 s
Total time: 9e-06 s
File: <ipython-input-4-dae73707787c>
Function: do_other_stuff at line 4
Line # Hits Time Per Hit % Time Line Contents
==============================================================
4 def do_other_stuff(numbers):
5 1 9 9.0 100.0 s = sum(numbers)
Total time: 0.000694 s
File: <ipython-input-4-dae73707787c>
Function: do_stuff at line 7
Line # Hits Time Per Hit % Time Line Contents
==============================================================
7 def do_stuff(numbers):
8 1 12 12.0 1.7 do_other_stuff(numbers)
9 1 208 208.0 30.0 l = [numbers[i]/43 for i in range(len(numbers))]
10 1 474 474.0 68.3 m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
مع هذه المعلومات ، أنت تفعل ليس تحتاج إلى كسر phes
حتى في وظائف فرعية متعددة ، لأنه يمكن أن ترى بدقة الخطوط التي لديها أعلى وقت للتنفيذ.
بما أنك ذكرت أن البرنامج النصي الخاص بك على المدى الطويل ، فإنني أوصي باستخدامه line_profiler
في عدد محدود من الطرق قدر الإمكان ، لأنه أثناء الإضافات يضيف النفقات العامة الإضافية ، يمكن لتوصيف الخط أن يضيف المزيد.