یکی از چیزهایی که فرترن بازها خیلی ادعاش رو میکنن سرعت زیاد کدهای محاسباتیشونه. خوب البته تو کار ما این مساله خیلی هم اهمیت داره. یه سری که با یکی از بچههای کامپیوتری سر این مساله بحث بود بدون تعصب ادعا میکرد که چند تا بنچ مارک برای محاسبات ماتریسی گرفته و تو اونها فرترن سریعتر از C بوده. این قضیه واسه من عجیب بود. یه سرچ زدم و دیدم که بله. این قضیه تا حدودی درسته. علت هم اینه که زبون C عزیز ما به علت این که یه زبون سطح پایین محسوب میشه تو حلقههانمیتونه مطمئن باشه که مقادیر متغیرها دست نخورده میمونه و به همین علت مرتب اونها رو آپدیت میکنه. بزارید یه مثال بزنم.
۱ ۲ ۳ ۴ ۵ |
for(int i=۰;i<n;++i) { out1[i]=۲*in[i]; out2[i]=۳*in[i]; } |
توی کد بالا کامپایلر C دو بار مقدار in[i] رو لود میکنه. علتش هم اینه که ممکنه اشارهگر in و out1 یکسان باشن. تو این حالت با هربار تغییر out1 در واقع داره in هم تغییر میکنه.
راه حل؟ استفاده از کلمه کلیدی restrict. اول بگم که این کلمه یه مقداری وابسته به کامپایلره. با استفاده از این کلمه کلیدی در واقع به کامپایلر قول میدیم که اشارهگر هامون به یه جا اشاره نمیکنن و در نتیجه کامپایلر لازم نیست نگران این مساله باشه. این کلمه کلیدی رو به دو شکل میشه به کار برد:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ |
void f1(int n, int *__restrict in, int *__restrict out1, int *__restrict out2) { for(int i=۰;i<n;++i) { out1[i]=۲*in[i]; out2[i]=۳*in[i]; } } |
یا اگه همه متغیرها همین وضع رو دارن و داریم از این روش تو یه کلاس استفاده میکنیم:
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ |
void myclass::f1(int n, int * in, int * out1, int * out2) __restrict { for(int i=۰;i<n;++i) { out1[i]=۲*in[i]; out2[i]=۳*in[i]; } } |
آپدیت مهم: همین الان یه بنچمارک خوب بین C و فرترن گرفتم. یه الگوریتم دقیقا به صورت یکسان با C و فرترن پیاده شده بود. بدون این تکنیک، سرعت کد C تقریبا نصف فرترن بود. با استفاده از این روش، زمان محاسباتی برنامه C به ۶۵٪ کد فرترن کاهش پیدا کرد. با تشکر از حبیب عبدی عزیز برای پیادهسازیش.