PDA

View Full Version : كدام بهتر است



A.Nemati
سه شنبه 25 خرداد 1389, 17:19 عصر
كدام يك از Syntax هاي زير بهتر است
1-


If DBase.FieldByName('Name').AsString <> '' then
lblName.Caption:= DBase.FieldByName('Name').AsString

2-


var tmpStr: String
...
tmpStr:= DBase.FieldByName('Name').AsString
If tmpStr <> '' then
lblName.Caption:= tmpStr

استفاده از DBase فقط براي نمونه است. شبيه اين مي‌تواند كلاس‌هاي ديگري نيز رخ دهد.
در كد اول، دوبار به يك پراپرتي رجوع شده كه ممكن است هر بار براي پاسخ به آن مسيري طي شود و دستوراتي انجام شوند تا به نتيجه رسيده و پاسخ گرفته شود. آيا پاسخ Cache مي‌شود؟ اگر Cache نشود، پس ممكن است كد دوم بهتر باشد. درست است كه يك انتساب رشته‌اي انجام شده است ولي مسير بدست آوردن پاسخ فقط يكبار طي شده و در واقع پاسخ را دستي Cache كرده‌ايم.
ما در برنامه‌هايمان بارها و بارها از اين نوع كدها استفاده مي‌كنيم. مي‌خواهم بدانم كدام يك از اين كدها بهينه هستند.

majid_ramak
چهارشنبه 26 خرداد 1389, 09:33 صبح
فکر میکنم روش اول صحیح تره به این دلیل که:
شما در روش دوم با ایجاد یک متغیر از نوع string بخشی از فضا رو اشغال کردین که این مورد لزومی نداره چون شما همین کار رو در روش اول بدون اینکه متغیری تعریف کنید و فضایی اشغال کنید انجام دادین، ثانیا اینکه در برنامه نویسی شی گرا سعی میکنن تا اونجا که ممکنه کمتر از تعریف متغیر ها استفاده کنند مگر در مواقعی خاص و بر حسب نیاز برنامه نویس .

vcldeveloper
چهارشنبه 26 خرداد 1389, 11:11 صبح
آيا پاسخ Cache مي‌شود؟ اگر Cache نشود، پس ممكن است كد دوم بهتر باشد.
نه، در موردی که مثال زدید (دسترسی به مقدار یک فیلد)، چیزی Cache نمیشه، و هر بار فراخوانی اون کد، باعث اجرای مجموعه ایی از دستورات، برای دسترسی به مقدار فیلد میشه. در سایر موارد، بستگی به پیاده سازی اون عملیات داره، یک کلاس ممکنه داده هایی را Cache کنه.


ما در برنامه‌هايمان بارها و بارها از اين نوع كدها استفاده مي‌كنيم. مي‌خواهم بدانم كدام يك از اين كدها بهينه هستند.
اگر فیلدها را به صورت Static تعریف کردید (دابل کلیک بر روی دیتاست مربوطه، و انتخاب گزینه Add All Fields)؛ در اون صورت، از نظر کارایی بهتر هست که از طریق شی فیلد ساخته شده به داده فیلد دسترسی پیدا کنید. مثلا اگر دیتاست شما اسمش MyDataset باشه، و یک فیلد Interger با نام ID داشته باشه، دلفی یک شی با نام MyDatasetID از نوع TIntegerField براتون ایجاد میکنه. مزیت استفاده از آن این هست، که برخلاف FieldByName، در هر بار دسترسی به فیلد مربوطه، برنامه مجبور نیست در لیست فیلدهای دیتاست به دنبال فیلد مربوطه بگرده. البته در صورتی که نام فیلدی را بعدا تغییر بدید، یا دیتاست شما کوئری های مختلفی با فیلدهای مختلف ارسال میکنه، در اون صورت دیگه این روش برای شما کارایی لازم را نخواهد داشت.


ثانیا اینکه در برنامه نویسی شی گرا سعی میکنن تا اونجا که ممکنه کمتر از تعریف متغیر ها استفاده کنند مگر در مواقعی خاص و بر حسب نیاز برنامه نویس .
این مطلب رو از کجا آوردید؟ اون متغیری که ایشون در کدش آورده، میتونه یک فیلد از یک کلاس، یا یک متغیر محلی در یک متد از یک کلاس باشه.

A.Nemati
چهارشنبه 26 خرداد 1389, 18:01 عصر
از مطلبي كه در مورد ديتابيس عنوان كرديد ممنون ولي منظور من كلي بود و استفاده از ديتابيس فقط يك نمونه بود (كه ظاهرا سبب خير هم شد).
چيزي كه ذهن منو درگير كرده اينه كه در صورتي كه مجبور باشيم چندين بار مقدار را چك كنيم، آيا به طور كلي پروسه‌اي كه طي مي‌شه تا به اين مقدار برسيم،‌ هزينه بيشتري داره يا متغيري كه تعريف مي‌كنيم تا اون مقدار رو نگه داريم و ازش استفاده كنيم؟ كدام يك بهينه‌تر هستند؟
البته مي‌دونم كه اين بستگي به ساختار كلاس داره ولي بعضي مواقع ما نمي‌دونيم واقعا براي رسيدن به مقدار مورد نظر، چه مسيري طي مي‌شه. يك مثال ديگه:


lstNames: TListBox;
....
var i: integer;
str: string;
...
(1)
for i:=0 to lstNames.Items.Count - 1 do
if lstNames.Items[i] = '' then
lstNames.Items[i]:= 'N/A'
else if lstNames.Items[i] = '-' then
lstNames.Items[i]:= 'Deleted from List';

(2)
for i:=0 to lstNames.Items.Count - 1 do
begin
str:=lstNames.Items[i];
if str = '' then
lstNames.Items[i]:= 'N/A'
else if str = '-' then
lstNames.Items[i]:= 'Deleted from List';
end;

vcldeveloper
چهارشنبه 26 خرداد 1389, 20:54 عصر
البته مي‌دونم كه اين بستگي به ساختار كلاس داره ولي بعضي مواقع ما نمي‌دونيم واقعا براي رسيدن به مقدار مورد نظر، چه مسيري طي مي‌شه. يك مثال ديگه:
در مثال دوم، دسترسی به Items خیلی سربار بالایی نداره، و استفاده از متغیر جداگانه، خیلی بهبودی ایجاد نمیکنه.

استفاده از متغیر جداگانه میتونه در مواردی باعث افزایش کارایی بشه، ولی اگر همینطوری بی رویه ازش استفاده کنید، ممکنه در مواردی فقط باعث افزایش حافظه مصرفی برنامه بشید، بدون اینکه چیز خاصی به دست بیارید! باید با توجه به نوع کد مورد استفاده، روش مناسب را انتخاب کنید.
یک راه مناسب این هست که بررسی کنید در هر حالت، کامپایلر چه کد اسمبلی (یا حداقل چند خط کد اسمبلی) براتون تولید میکنه. برای این کار، می تونید روی کد BreakPoint بزارید، و از پنجره CPU برای بررسی کد اسمبلی تولید شده، استفاده کنید.

majid_ramak
پنج شنبه 27 خرداد 1389, 09:31 صبح
قبلا یک همچین سوالی از یکی از اساتید کردم که تفاوت این دو کد درچیه؟ (به جز اینکه در مثال اول فضای بیشتری مورد استفاده قرار گرفته)
برای مثال:
۱)

var
A, B, C: Integer;
begin
A:= StrToInt(Edit1.Text);
B:= StrToInt(Edit2.Text);
C:= A + B;
Edit3.Text:= IntToStr(C);
۲)

Edit3.Text:= IntToStr(StrToInt(Edit1.Text) + StrToInt(Edit2.Text));
جوابی که به من داد این بود:
در برنامه نویسی شی گرا بیشر با خود اشیا برای انتقال مقادیر استفاده می کنند تا تعریف متغیر ها (مگر بر حسب نیاز برنامه نویس) و گفت که این یکی از خاصیت های برنامه نویسی شی گرا ست، ثانیا در مثال دوم سرعت اجرای کد بیشر هست البته بسیار بسیار ناچیز هست.
البته نظراتش به نظرم معقول بود چون دیدم وقتی میشه از خود اشیا برای این کار استفاده کرد چه لزومی به تعریف مجدد از متغیر هاست.
حالا سوالی که از شما دارم ﺁقای کشاورز، میخواستم ببینم ﺁیا خلاف این هست یا نه صحبت ایشون درست بوده؟
با تشکر.

vcldeveloper
پنج شنبه 27 خرداد 1389, 20:58 عصر
قبلا یک همچین سوالی از یکی از اساتید کردم که تفاوت این دو کد درچیه؟ (به جز اینکه در مثال اول فضای بیشتری مورد استفاده قرار گرفته)
جوابی که به من داد این بود:
در برنامه نویسی شی گرا بیشر با خود اشیا برای انتقال مقادیر استفاده می کنند تا تعریف متغیر ها (مگر بر حسب نیاز برنامه نویس) و گفت که این یکی از خاصیت های برنامه نویسی شی گرا ست، ثانیا در مثال دوم سرعت اجرای کد بیشر هست البته بسیار بسیار ناچیز هست.برای اینکه تفاوت اون دو کد رو متوجه بشید:

کد تولید شده از سورس اول:


lea edx,[ebp-$04]
mov eax,[ebx+$00000388]
call TControl.GetText
mov eax,[ebp-$04]
call StrToInt
mov esi,eax
lea edx,[ebp-$08]
mov eax,[ebx+$0000038c]
call TControl.GetText
mov eax,[ebp-$08]
call StrToInt
lea ebx,[eax+esi]
lea edx,[ebp-$0c]
mov eax,ebx
call IntToStr
mov eax,[ebp-$0c]
call ShowMessage

کد تولید شده از سورس دوم:


lea edx,[ebp-$08]
mov eax,[ebx+$00000388]
call TControl.GetText
mov eax,[ebp-$08]
call StrToInt
mov esi,eax
lea edx,[ebp-$0c]
mov eax,[ebx+$0000038c]
call TControl.GetText
mov eax,[ebp-$0c]
call StrToInt
add esi,eax
mov eax,esi
lea edx,[ebp-$04]
call IntToStr
mov eax,[ebp-$04]
call ShowMessage

اگر دقت کنید، دو کد مورد نظر شما، تقریبا یک کد تولید کردند. حتی از نظر حافظه مصرفی خاصی با هم ندارند. این به خاطر Optimizationهایی هست که کامپایلر انجام میده.



در برنامه نویسی شی گرا بیشر با خود اشیا برای انتقال مقادیر استفاده می کنند تا تعریف متغیر ها (مگر بر حسب نیاز برنامه نویس) و گفت که این یکی از خاصیت های برنامه نویسی شی گرا ستاشیاء شما خودشون متغیر هستند. در برنامه نویسی شی گرا، شما از متغیرهای Global استفاده نمی کنید. متغیرهای استفاده شده در داخل یک شی، یا متغیرهای محلی داخل یک روتین هستند، یا فیلدهای همون کلاس، یا فیلدها و خصوصیات یک شی دیگه که با این شی در ارتباط هستند.

اون چیزی که منظور استاد شما بود، همون استفاده از متغیرهای Global بود. اون موضوع ربطی به بحث این تاپیک نداره. در این تاپیک، سوال این هست که وقتی نتیجه یک فرآیند در چندین بخش از کد استفاده میشه، آیا باید نتیجه فرآیند را یک بار در جایی Cache کرد، و در دفعات بعدی از اون مقدار Cache شده استفاده کرد؟ یا اینکه این کار به طور خودکار انجام میشه، و نیازی نیست که برنامه نویس همچین دغدغه ایی داشته باشه؟

همانطور که در پست های قبلی توضیح دادم، این مسئله به کد نوشته شده، و عملکرد آن فرآیند بستگی داره؛ در مثال مربوط به دسترسی به فیلد دیتاست، این کار باعث افزایش کارایی (در حد محدود) میشه. در مثال StrToInt و استفاده از متغیرهای جداگانه، تغییری در کارایی کد بوجود نمیاد.

البته بهتر هست که برنامه نویس این مورد رو مد نظر داشته باشه، و اگر محاسبه ایی مرتبا تکرار میشه، سعی کنه آن را جایی Cache کنه. همچنین، در مثال دومی که ارائه شد (همون مثال C := A + B)، خوانایی خود بیشتر، و دیباگ کد آسانتر هست. از آنجایی که یک کد یک بار نوشته میشه، و بارها خوانده میشه، و دیباگ میشه، و همچنین، با توجه به اینکه تفاوت کارایی هم به مرحمت Optimization کامپایلر وجود نداره، پس کد اول در اون مثال، بر کد دوم ارجحیت داره، و بهتر هست.