سلام من یه برنامه دارم که توی این برنامه یه حلقه هست که معمولا زمان زیادی رو برای تکمیل میگیره
از اون طرف برنامه فقط از یکی از هسته های سی پی یو استفاده میکنه
میشه منو راهنمایی کنید که کاری کنم برنامه از تمام قدرت سی پی یو استفاده کنه؟
ممنون:n16:
Printable View
سلام من یه برنامه دارم که توی این برنامه یه حلقه هست که معمولا زمان زیادی رو برای تکمیل میگیره
از اون طرف برنامه فقط از یکی از هسته های سی پی یو استفاده میکنه
میشه منو راهنمایی کنید که کاری کنم برنامه از تمام قدرت سی پی یو استفاده کنه؟
ممنون:n16:
1- می توانید از کلاس های Parallel استفاده کنید. در قبل برای حلقه در [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ] مثال زده ام.
2-می توانید از اجرای کدها به روش Multi Taskاستفاده کنید.
3- می توانید از اجرای کدها به روش Multi Thread استفاده کنید.
در هر صورت یک قطعه کد به صورت ساده CPU های نسل فعلی را مشغول نمی گرداند.
موفق باشید.
مشکلات (سوالات) در مورد Parallelنقل قول:
1) متاسفانه حلقه ی for که توی برنامه هست از double استفاده میکنه و تبدیل اون به long باعث کاهش دقت میشه، و Parallel از double پشتیبانی نمیکنه:n03:
2) من یک حلقه ساده ایجاد میکنم به این صورت:
اما جواب بجای 100000 یک عدد دیگه در حدود 50000 هست، انگار با اینکه ظاهرا تمام هسته ها درگیر هستند ولی فقط تغییراتی که توسط یک هسته ایجاد میشه در نظر گرفته میشه، یا...کد:int j = 0;
Parallel.For(0, 100000, (long i) =>
{
j++;
});
Console.WriteLine(j);
ببخشید من کمتر از 2 ساعت هست با Parallel آشنا شدم و اشتباهات زیادی دارم.
در مورد دو مورد بعد فکر میکنم باید حلقم رو به چند بخش تقسیم کنم و هر بخش رو به یک Thread بدم برای اجرا(کار سختیه)، درسته؟
ممنون از پاسخ سریع:n16:
حدس بزنید چرا به جای 100000 شما یک عدد دیگر می گیرید؟؟؟؟
فرض: یکی از هسته ها می خواهد ثبت کنه اون یکی داره می خونه و اون یکی هم داره حاصل جمع رو میریزه! اوه اوه چه شیر تو شیریه!
برای همین برخی حاصل جمع های شما از بین میره.برای این که عمل درست شود اینگونه باید بنویسید:
خوب این کد یک مشکل اجرایی اساسی دارد. اول امتحان کنید بعد خط های بعدی را بخوانید.کد:int j = 0;
object locker= new object();
System.Diagnostics.Stopwatch stp = new System.Diagnostics.Stopwatch();
stp.Start();
Parallel.For(0, int.MaxValue, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate(int i)
{
lock (locker)
{
j++;
}
});
stp.Stop();
Console.WriteLine(stp.Elapsed);
Console.ReadKey();
}
--------------------------------------------------------------------
--------------------------------------------------------------------
--------------------------------------------------------------------
--------------------------------------------------------------------
--------------------------------------------------------------------
مشکل چیست؟ مشکل در سرعت اجراست. اگر قرار باشد چند هسته بیشتر از یک هسته طول بکشد که ..............
چرا طول می کشد؟ Lock یک عبارت کند است و به شدت کاهش سرعت ایجاد می کند.
پس باید الگوریتم را کمی تغییر دهیم:
الان پس از هر محاسبه مقدار جایگزین می شود و این کار تنها lock را در پایان هر Thread از پارالل اجرا می کند نه هر دفعه.کد:Parallel.For(0, int.MaxValue, InitValues, RunInPerThreadOnLoop, RunAfterThreadLoop);
static object locker = new object();
static int sum = 0;
static int InitValues() {
return 0;
}
static int RunInPerThreadOnLoop(int i, ParallelLoopState state, int inernalSum)
{
inernalSum ++;
return inernalSum;
}
static void RunAfterThreadLoop(int inernalSum)
{
lock (locker)
{
sum += inernalSum;
}
}
برای کنترل بیشتر در این ساختار نیز:
در حالت عادی مثل بالا این overload فقط int را به عنوان آرگومان پاس و پس می گیرد. برای رفع محدودیت از نوع ارسال آرگومان و بازگشتی می توان توع آرگومان را اینگونه تغییر داد:کد:Parallel.For(0, int.MaxValue, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, InitValues, RunInPerThreadOnLoop, RunAfterThreadLoop);
پس متدهایمان نیز اینگونه می شوند:کد:Parallel.For<double>(0, int.MaxValue, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, InitValues, RunInPerThreadOnLoop, RunAfterThreadLoop);
موفق باشید.کد:static double InitValues() {
return 0;
}
static double RunInPerThreadOnLoop(int i, ParallelLoopState state, double inernalSum)
{
inernalSum ++;
return inernalSum;
}
static void RunAfterThreadLoop(double inernalSum)
{
lock (locker)
{
sum += inernalSum;
}
}
بیست و محشر!!!
بسیار ممنون، سعی میکنم تا عصر کد هام رو به این صورت تغییر بدم تا ببینم چی میشه. :n11:
------------------------------------------------
نه به یک مشکلی برخوردم، من شمارنده هام double هاست نه تابع
مثلا:
سعی میکنم تعداد حلقه رو مشخص کنم و از long استفاده کنمکد:for(double i=1.43245;i<7.5435;i+=0.00321)
؟نقل قول:
ما هم شمارنده داشتیم. نه تابع!
اون متدها وظیفه شمارش را داشتند. نه اینکه خودشون شمارش بشن.
من مثال double برای Parallel را هم قرار داده ام. آخرین قسمت پست قبل.
موفق باشید.