----- کاهش انتقال اطلاعات در حافظه پشته
(اخطار! این مطلب را فقط باید در برنامه نویسی های سه بعدی رعایت کنید و عدم رعایت و پیاده سازی این مطالب در سایر برنامه ها سودش بیشتر از ضررش است!)
محل استاندارد نگه داری و ذخیره Struct ها در حافظه پشته است.
و حتماً میدانید که این به نوعی مختص همان متدی است که الآن دارد اجرا میشود.
نتیجتاً برای انتقال اطلاعات به/از متد رایانه مجبور میشود دیتاها را جابه جا کند و به پشته مناسب دیگر انتقال بدهد.
(این مطلب ربط خاصی به زبان و محیط برنامه نویسی هم ندارد و تقریباً در همه زبانهای برنامه نویسی وجود دارد)
به تابع زیر دقت کنید:
کد:
کد:
//C#.Net
public structtyep1 Func1(structtype2 x, ref structtype3 y, classtype z)
{
//...
}
'VB.Net
Public Function Func1(ByVal x As structtype2, ByRef y As structtype3, ByVal z As classtype) As structtyep1
'...
End Function
این یک تابع نمونه است که سه پارامتر میگیرد و یک پارامتر پس میدهد...
نتیجتاً و کلاً 4 پارامتر ورودی خروجی دارد که باید به/از پشته منتقل شود.
اما هر آرگومان ورودی خروجی فوق چه حجم کپی را به سیستم تحمیل میکند؟
1- آرگومان x:
تعداد بایتهای کپی برابر حجم بایتی struct است
(مثلاً
int=float=4Byte
datetime=double=8Byte
XNA.Vector3=12Byte
XNA.Matrix=64Byte
و...
)
2- آرگومان y:
چون byref است فقط اشاره گرش کپی میشود که در یک سیستم 32 بیتی 32 بیت و برابر 4 بایت است.
یعنی بدون توجه به حجم struct و نوع ان فقط 4 بایت اشاره گر منتقل میشود.
3- آرگومان z:
چون class است و اصلاً ربطی به پشته ندارد، فقط همان اشاره گر 4 بایتی اش کپی میشود.
4- آرگومان بازگشتی از نوع structtype1
مثل آرگومان x است و به اندازه حجمش کپی میشود البته در جهت عکس x که چندان فرقی ندارد!
خوب حالا نتیجه ؟
نتیجه اخلاقی(!)، فلسفی(!)، علمی مطلب فوق ان است که اگر struct ای بخواهد به تابعی پاس داده شود و یا گرفته شود، و اگر ان struct بزرگتر از 4 بایت (و ترجیحاً بزرگتر از 8 بایت) باشد ارجاع اشاره گری آن بهتر و بهینه تر است و حجم کمتری پردازش و هزینه را در بر دارد.
البته ارسال اشاره گری این خطر بزرگ را دارد که عمدی یا سهوی و یا با خطا و... مقدار متغییر در داخل متد و روال تغییر کند در حالی که ما اصلاً نمیخواستیم این مقدار در متد عوض شود و میخواستیم فقط ان را بخواند...
ولی خوب یک کم اگر حواستان جمع باشد و اعتماد داشته باشید در برنامه های سه بعدی خوب است!
مایکروسافت هم در همین جهت در توابع خود دو دسته کد و ورودی خروجی را سازمان داده ...
به دو کد زیر دقت کنید:
کد:
کد:
//C#.Net
XNA.Vector3 v1, v2, v3;
//کد اول
//public static XNA.Vector3 Cross(XNA.Vector3 vector1, XNA.Vector3 vector2);
v3 = XNA.Vector3.Cross(v1, v2);
//کد دوم
//public static void Cross(ref XNA.Vector3 vector1, ref XNA.Vector3 vector2, out XNA.Vector3 result);
XNA.Vector3.Cross(ref v1, ref v2, out v3)
'VB.Net
Dim v1, v2, v3 As XNA.Vector3
'کد اول
'Public Shared Function Cross(ByVal vector1 As XNA.Vector3, ByVal vector2 As XNA.Vector3) As XNA.Vector3
v3 = XNA.Vector3.Cross(v1, v2)
'کد دوم
'Public Shared Sub Cross(ByRef vector1 As XNA.Vector3, ByRef vector2 As XNA.Vector3, <Out> ByRef result As XNA.Vector3)
XNA.Vector3.Cross(v1, v2, v3)
این دو کد دقیقاً یک عمل را انجام میدهند.
ولی کد اول در حالت تئوری حداقل 36 بایت را در عملیات خود کپی میکند در حالی که کد دوم در حالت تئوری فقط موجب کپی 12 بایت میشود!
=====
اگر خودتان میخواهید توابعی با الگوی ورودی خروجی دوم بنویسید و در پروژه تان استفاده کنید ... باید باید باید حواستان باشد و مطمئن مطمئن شوید که در نوشتن تابعی با الگوی دوم اشتباهاً مقدار یک پارامتر ورودی byref را در کد تغییر ندهید.
یک مثال دیگر از ضرب سه ماتریس به دو روش!
کد:
کد:
//C#.Net
XNA.Matrix m1, m2, m3, m4;
//کد اول
m4 = m1 * m2 * m3;
//کد دوم
XNA.Matrix t;
XNA.Matrix.Multiply(ref m1, ref m2, out t);
XNA.Matrix.Multiply(ref t, ref m3, out m4);
'VB.Net
Dim m1, m2, m3, m4 As XNA.Matrix
'کد اول
m4 = m1 * m2 * m3
'کد دوم
Dim t As XNA.Matrix
XNA.Matrix.Multiply(m1, m2, t)
XNA.Matrix.Multiply(t, m3, m4)
این دو کد دقیقاً یک نتیجه دارند ولی برخلاف ظاهر دو کد مطمئن باشید کد دوم بسیار سریعتر اجرا میشود.
کد اول در حالت تئوری حداقل موجب 384 بایت انتقال اطلاعات در پشته میشود ولی کد دوم در حالت تئوری فقط موجب 24 بایت انتقال اطلاعات بین پشته میشود !!!!!! (حساب نکنید! 16 برابر کمتر میشود!)
1- بحث سر تفاوت 360 تک بایت نیست، مشکل سر همان حلقه های پنهانی است که اغلب متوجه شان نمیشودی ولی باعث میشود یک خط کد شما در برنامه های سه بعدی بارها و بارها و بارها اجرا شود و صفرهای ناقابل را در جلوی هزینه ها اضافه کند!
2- قطره قطره جمع گردد و بانگهی دریا شود.
(
البته این را هم اضافه کنم که به علت سادگی بیشتر کد اول و درک راحت تر آن در کدهای اتی این آموزش احتمالاً از همان کد اول استفاده خواهد شد و کدهای آتی ارائه شده در این اموزش لزوماً بهترین کدها نیستند و در این تاپیک اولویت با سادگی و قابل فهم بیشتر بودن کدها خواهد بود.
نتیجتاً شما باید این موارد را رعایت کنید ولی من برای کدهای این تاپیک شاید در جهت منافع آموزشی انها را رعایت نکنم.
به این میگن حق وتوی دات نتی!