Software Engineering for Data Scientists: Analyzing Code Performance
فصل دوم از کتاب به سراغ مساله performance کد میره. اولین مساله اینه که کد باید درست کار کنه و حالا بعد سراغ performance اش بریم. معنی نداره کدی داشته باشید که کار نکنه و بخواید از نظر performance ای بهبودش بدید (گرچه سناریو متداولی برای افراد وسواسی هست). مساله بعدی اینه که نیازمندیهای performance ای خودمون رو باید مشخص کنیم. مثلا بدونیم در حداکثر چند ثانیه باید جواب برگردونیم یا چه قدر مموری مجازیم مصرف کنیم. یک سخن بزرگانی هست در این خصوص که میگه:
premature optimization is the root of all evil in programming.
(بنده اما همین جمله رو به زندگی هم تعمیمش میدم. چرا که خودم در زندگی از این اشتباه زیاد زخم خوردم و بدبخت شدم)
مساله بعدی اینه که حالا که هم یک کدی داریم که داره درست کار میکنه و هم نیازمندی performance ای خودمون رو میدونیم بفهمیم کدوم قسمت از کد ما داره کار رو خراب میکنه و اونها رو ردیفشون کنیم.
کجاها رو میتونیم ور بریم تا performance مون بهتر بشه؟
گزینههای روی میز اینان:
- الگوریتم و نوع پیادهسازیهاتون. مثلا این که از nested loop بپرهیزیم و کار رو با ضرب ماتریسی بعضی جاها دربیاریم
- انتخاب دادهساختار درست. مثلا این که کجا از numpy و pandas و به چه نحوی استفاده کنیم که در فصل بعدی انشالله بهش میرسم
- استفاده از توابع built-in. خیلی از توابع پایتون و کتابخونههاش، با C زده شدند و یا جوری زده شدند که efficient هستند. پس عقلانیه که از اونها استفاده کنیم.
- کامپایلکردن پایتون. مثلا برای سریعتر اجرا گرفتن از یک کد پایتون میشه به یک کد سطح پایینتر نظیر cython کامپایلش کرد.
- امکان asynchronous کردن. اگر میشه در پیادهسازی اگر جایی میشد async عمل کرد این کار رو بکنیم. یعنی مثلا اگر جایی نیاز به یک api ریکوئست زدیم و نیاز نبود که منتظر بشیم async کد رو بزنیم.
- موازیکاری. اگر میشد کدمون رو به صورت multiprocesing و یا distributed بزنیم. در اولی کد ما روی چندین cpu اجرا میشه و در دومی روی چندین ماشین.
چه جوری بفهمیم کجای کد، زمان و مموری رو خرج میکنه؟
ایده بدیهی و dummy اش اینه که از time.time پایتون استفاده کنیم و خط به خط رو تست بگیریم. یک مرحله هوشمندانهتر اینه که چندین بار اجرا بگیریم تا تخمین بهتری دستمون بیاد. برای این کار میشه از timeit استفاده کرد. در ژوپیتر نوتبوک هم برای هر سلول میشه از timeit%% استفاده کرد.
مشکل timeit اینه که به درد مثلا یک خط میخوره. اگر حالا خواستیم کل کدمون رو کنترل کنیم چی؟ میشه از cProfile استفاده کرد (اصطلاحش هم کلا Profiling کد هست).
برای پروفایلکردن مموری هم میشه از Memray استفاده کرد.
سواربودن روی پیچیدگی زمانی الگوریتم
باقی فصل هم یک سری صحبتها راجع به پیچیدگی زمانی الگوریتمها و لزوم حواس جمعبودن روش حرف میزنه که به نظر بدیهی میان.