की तुलना में एकाधिक कोर पर 4x धीमी क्यों चलती है, मैं समझने की कोशिश कर रहा हूं कि सीपीथन के जीआईएल कैसे काम करता है और सीपीथन 2.7.एक्स और सीपीथन 3.4.x में जीआईएल के बीच अंतर क्या है। मैं बेंचमार्किंग के लिए इस कोड का उपयोग कर रहा हूँ:यह पाइथन लिपि एक कोर
from __future__ import print_function
import argparse
import resource
import sys
import threading
import time
def countdown(n):
while n > 0:
n -= 1
def get_time():
stats = resource.getrusage(resource.RUSAGE_SELF)
total_cpu_time = stats.ru_utime + stats.ru_stime
return time.time(), total_cpu_time, stats.ru_utime, stats.ru_stime
def get_time_diff(start_time, end_time):
return tuple((end-start) for start, end in zip(start_time, end_time))
def main(total_cycles, max_threads, no_headers=False):
header = ("%4s %8s %8s %8s %8s %8s %8s %8s %8s" %
("#t", "seq_r", "seq_c", "seq_u", "seq_s",
"par_r", "par_c", "par_u", "par_s"))
row_format = ("%(threads)4d "
"%(seq_r)8.2f %(seq_c)8.2f %(seq_u)8.2f %(seq_s)8.2f "
"%(par_r)8.2f %(par_c)8.2f %(par_u)8.2f %(par_s)8.2f")
if not no_headers:
print(header)
for thread_count in range(1, max_threads+1):
# We don't care about a few lost cycles
cycles = total_cycles // thread_count
threads = [threading.Thread(target=countdown, args=(cycles,))
for i in range(thread_count)]
start_time = get_time()
for thread in threads:
thread.start()
thread.join()
end_time = get_time()
sequential = get_time_diff(start_time, end_time)
threads = [threading.Thread(target=countdown, args=(cycles,))
for i in range(thread_count)]
start_time = get_time()
for thread in threads:
thread.start()
for thread in threads:
thread.join()
end_time = get_time()
parallel = get_time_diff(start_time, end_time)
print(row_format % {"threads": thread_count,
"seq_r": sequential[0],
"seq_c": sequential[1],
"seq_u": sequential[2],
"seq_s": sequential[3],
"par_r": parallel[0],
"par_c": parallel[1],
"par_u": parallel[2],
"par_s": parallel[3]})
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("max_threads", nargs="?",
type=int, default=5)
arg_parser.add_argument("total_cycles", nargs="?",
type=int, default=50000000)
arg_parser.add_argument("--no-headers",
action="store_true")
args = arg_parser.parse_args()
sys.exit(main(args.total_cycles, args.max_threads, args.no_headers))
जब अजगर 2.7.6 के साथ Ubuntu 14.04 के तहत मेरे क्वाड-कोर i5-2500 मशीन पर इस स्क्रिप्ट चल रहा है, मैं निम्नलिखित परिणाम (_R वास्तविक समय के लिए खड़ा है, CPU समय के लिए _c, उपयोगकर्ता मोड के लिए _u, कर्नेल मोड के लिए _S):
#t seq_r seq_c seq_u seq_s par_r par_c par_u par_s
1 1.47 1.47 1.47 0.00 1.46 1.46 1.46 0.00
2 1.74 1.74 1.74 0.00 3.33 5.45 3.52 1.93
3 1.87 1.90 1.90 0.00 3.08 6.42 3.77 2.65
4 1.78 1.83 1.83 0.00 3.73 6.18 3.88 2.30
5 1.73 1.79 1.79 0.00 3.74 6.26 3.87 2.39
अब अगर मैं एक कोर करने के लिए सभी धागे बाँध, परिणाम बहुत अलग हैं:
taskset -c 0 python countdown.py
#t seq_r seq_c seq_u seq_s par_r par_c par_u par_s
1 1.46 1.46 1.46 0.00 1.46 1.46 1.46 0.00
2 1.74 1.74 1.73 0.00 1.69 1.68 1.68 0.00
3 1.47 1.47 1.47 0.00 1.58 1.58 1.54 0.04
4 1.74 1.74 1.74 0.00 2.02 2.02 1.87 0.15
5 1.46 1.46 1.46 0.00 1.91 1.90 1.75 0.15
तो सवाल यह है : इस पायथन क्यों चल रहा है एकाधिक कोर पर कोड 1.5x-2x धीमी दीवार घड़ी और 4x-5x धीमी गति से CPU घड़ी द्वारा इसे एक कोर पर चलाने की तुलना में धीमा है?
आसपास पूछ और दो परिकल्पना का उत्पादन किया googling:
- जब कई कोर पर चल रहा है, एक धागा एक अलग कोर जिसका अर्थ है स्थानीय कैश अवैध हो जाता है, इसलिए मंदी पर चलाने के लिए फिर से निर्धारित किया जा सकता।
- एक कोर पर धागे को निलंबित करने और इसे किसी अन्य कोर पर सक्रिय करने के ऊपरी हिस्से को उसी कोर पर थ्रेड को निलंबित करने और सक्रिय करने से बड़ा है।
क्या कोई अन्य कारण हैं? मैं समझना चाहता हूं कि क्या हो रहा है और संख्याओं के साथ मेरी समझ को वापस करने में सक्षम होने के लिए (जिसका अर्थ है कि अगर मंदी की वजह से मंदी की वजह है, तो मैं दोनों मामलों के लिए संख्याओं को देखना और तुलना करना चाहता हूं)।
हां, मुझे जीआईएल के बारे में पता है और मुझे आश्चर्य नहीं है कि समांतर धागे में उलटी गिनती चलाना वास्तव में एक धागे की तुलना में धीमी है। मुझे क्या आश्चर्य है और मुझे समझ में नहीं आता है कि इस कोर को एकाधिक कोर पर क्यों चलाना एक कोर पर चलने से इतना धीमा है। – user108884
मैंने देखा कि पहले संस्करण में रिपोर्ट किए गए समय को जोड़ने के दौरान (इसलिए टास्कसेट के बिना), राशि 'समय' द्वारा रिपोर्ट किए गए समय के अनुरूप नहीं थी। यदि 'time.clock()' को 'time.time()' में बदल दिया गया है, तो यह विसंगति दूर हो जाती है। हालांकि, 'टास्कसेट' दृष्टिकोण का उपयोग करते समय अभी भी थोड़ा सा फायदा होता है, यह सुनिश्चित नहीं है कि इसका क्या अर्थ है ... – brm
* nix time.clock() पर CPU समय रिपोर्ट करता है, दीवार घड़ी समय नहीं (https: // दस्तावेज़। python.org/2.7/library/time.html#time.clock)। तो परिणामों को इस तरह से व्याख्या किया जाना चाहिए: इस कोड को एकल कोर की तुलना में एकाधिक कोर पर चलाने के लिए बहुत अधिक CPU प्रयास करना पड़ता है। मैं इन परिणामों पर ठोकर खाने वाला पहला व्यक्ति नहीं हूं (उदा। Https://youtu.be/Obt-vMVdM8s?t=55s), लेकिन मैं स्पष्टीकरण से संतुष्ट नहीं हूं। लेकिन आप सही हैं, मुझे वास्तविक समय को मापना और रिपोर्ट करना चाहिए। मैं कोड अपडेट करूंगा। – user108884