Streamهای جاوا ۸ چقدر سریع هستند؟
بعد از انتشار نسخه ۸ جاوا، احتمالا اسم استریمهای جاوا ۸ به گوشتان خورده است یا حتی کار با آنها را امتحان کردهاید. اما سوالی که مطرح میشود این است که در مقایسه با containerهای دیگر جاوا، آیا واقعا سریعتر هستند؟
جاوا ۸ با یک تغییر عمده نسبت به نسخههای قدیمی خود منتشر شد و آن اضافه کردن stream API بوده است. مشابه collectionها، استریمها برای نمایش یک دنباله از المانها به کار میروند. مفهوم استریمهای جاوا از برنامهنویسی functional الهام گرفته شده است که نشان میدهد جاوا اجازه نوشتن کدها به فرمت functional را هرچند به طور محدود به کاربران میدهد. برای شناخت بیشتر از این قابلیت اضافه شده در جاوا ۸ میتوانید به این مطلب مراجعه کنید. در اینجا میخواهیم سرعت اجرای برنامههای مشابه با استفاده از استریم و حلقههای for سابق جاوا را مقایسه کنیم.
در اینجا عملیات حجیم با استفاده از استریمهای ترتیبی و حلقههای for سابق را مقایسه میکنیم. میخواهیم بررسی کنیم آیا واقعا استفاده از استریمها ارزش دارد؟
یک آرایه عدد صحیح حاوی ۵۰۰،۰۰۰ عدد تصادفی را در نظر میگیریم و در آن به دنبال ماکزیمم مقدار خواهیم گشت. به فرمت قدیمی کد آن به شکل زیر است:
int[] a = ints; int e = ints.length; int m = Integer.MIN_VALUE; for(int i=0; i < e; i++) if(a[i] > m) m = a[i];
با استفاده از استریم های ترتیبی کد فوق به شکل زیر قابل پیادهسازی است:
int m = Arrays.stream(ints) .reduce(Integer.MIN_VALUE, Math::max);
در اندازهگیری که روی یک سیستم قدیمی (دو هستهای بدون dynamic overclocking) و با گرم شدن طبیعی آن انجام گرفت نتیجه اندازهگیری به شکل زیر بوده است:
int-array, for-loop : 0.36 ms
int-array, seq. stream: 5.35 ms
نتیجه آن مدهوش کننده است! حلقههای for سابق ۱۵ برابر سریعتر از استریم عمل کردند. ناامیدکننده است! سالها تلاش برای توسعه استریمها در جاوا ۸ در نهایت این شد؟!… اما صبر کنید! قبل از نتیجهگیری نهایی بگذارید یک بار به جای آرایه اعداد صحیح از لیستهای سابق استفاده کنیم و آزمایش را تکرار کنیم.
با استفاده از حلقه for داریم:
int m = Integer.MIN_VALUE; for (int i : myList) if (i>m) m=i;
و با استفاده از استریمهای ترتیبی نیز مشابه قسمت قبل داریم:
int m = myList.stream() .reduce(Integer.MIN_VALUE, Math::max);
نتیجه اندازهگیری به شکل زیر است:
ArrayList, for-loop : 6.55 ms
ArrayList, seq. stream: 8.33 ms
مجددا حلقه for سریعتر عمل کرد اما اینبار با اختلاف کمتری از استریمها آزمایش انجام گرفت.
آزمایش اول را این بار روی یک سیستم با سختافزار جدید( دارای ۴ هسته مجازی) اجرا میکنیم. در اجرا روی آرایهها این بار هم حلقه سریعتر عمل میکند اما با نسبت ۴.۲ (به جای ۱۵ برابر) پس میزان اختلاف در محیطهای متفاوت نیز متفاوت است اما نتیجهگیری کلی که حلقه for از استریمهای ترتیبی سریعتر است کماکان برقرار است.
پس ارتقا کارایی که استریمها برای آن ساخته شده بودند کجاست؟
البته این مطلب همه ماجرا نیست. بخش تحلیل نتایج و جمعبندی این مقاله را در مطلب دیگری حضورتان ارائه میکنیم تا اندکی خودتان در مورد دلایل این نتایج بیندیشید و ذهن خود را تمرین دهید 🙂
میتوانید نتایج افکار خود را در قسمت نظرات با ما در میان بگذارید.
منبع:
https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html
در این مقاله اشاره شده که کامپایلرها سال ها روی بهینه کردن حلقه های تکرار کار کرده اند و تا حد ممکن هم نتیجه بخش بوده است.
بنابرین طراحان جاوا 8 بر روی قابلیتهای سخت افزارهای جدید تمرکز داشته اند تا بتوانند مثلا اجرای برنامه را به سمت موازی سازی پیش ببرند
قابلیتهای موازی سازی که در stream ها گذاشته شده است نمی تواند به بهبود کارایی کمک کند؟
بله میتواند. اما نه در هر شرایطی و نه به مقداری که انتظار میرود. (یعنی روی پردازنده دو هستهای سرعت اجرای استریم موازی نسبت به ترتیبی دو برابر نخواهد شد و کمتر از آن است)
در کل در این متن همانطور که اشاره شده است استریمهای ترتیبی (sequential streams) مورد بررسی قرار گرفتهاند.
به نظرم در سخت افزارهای چند پردازنده تاثیر گزار است
تو این مقاله نشون میده که در استفاده از استریم ها باید یکسری نکات ریز رو در نظر بگیریم تا بتونیم ازشون بهینه استفاده کنیم.
http://blog.takipi.com/benchmark-how-java-8-lambdas-and-streams-can-make-your-code-5-times-slower/
شاید واقعا از نظر سرعت عملکرد، استریم ها نسبت به ساختار های گذشته بهبودی نداشته اند و فقط از نظر خوانایی کد، کار برنامه نویسانی که میخواهند کد نوشته شده را بخوانند را راحت میکنه
ولی کلا چرا باید راحت تر کنه؟ مگر غیر اینه که ما باید دونه دونه خانه های آرایه ها رو بخوانیم و چک کنیم؟ در واقع این بررسی ما order n نیست مگه؟
شاید با هدف Stream ها آشنا نیستم ( شاید که نه، خوب نیستم دیگه :)))) )