PDA

View Full Version : تناقض در رفتار حلقه Parallel.For



ad hoc
پنج شنبه 02 دی 1395, 10:14 صبح
با سلام حدمت دوستان عزیز
یک برنامه ساده را مثال می زنم خدمتتان که با Parallel.For موازی سازی شده و جالب اینجاست که تا وقتی از MessageBox.Show جهت نمایش پیغام استفاده شود، درست کار می کند اما با حذف آن نتایج چاپ شده در تکست باکس خروجی تکراری می شود

Parallel.For(0, allPairs, j =>


{


MessageBox.Show("j is :"+j); متن این مسیج باکس هر چیزی می تواند باشد ، مهم اینجاست که تا وقتی این مسیج باکس هست برنامه درست کار می کند


Tagging(j);


});



private void Tagging( int PairNumber)
{


Random R = new Random();


int Random1 , Random2;
Random1 = R.Next(0, 100000);
// یک عدد تصادفی تولید می شود


if ((Random1 % 2 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "G";
if ((Random1 % 3 == 0) || (Random1 % 5 == 0)) StateF[(PairNumbe )] = "L";
else StateF[(PairNumber)] = "S";

// براساس اینکه عدد تصادفی مان چه بوده است، یک برچسب ایجاد می شود ، S ،L یا G




کار برنامه هم که مشخصه . به شکل تصادفی و البته طبق قوانینی، باید به اندازه طول آرایه StateF ، برچسبهای S،LیاG چاپ شود
منتهی با حذف messageBox همه حالتها تکراری می شوند
احتمالا جایی را اشتباه کرده باشم ولی متوجه آن نمی شوم !!

ممنون می شوم که راهنماییم کنید یا نظرتان را بفرمایید :لبخندساده:



کد در ادامه :



namespace Test_SLG
{
public partial class Form1 : Form
{
int PairNumber;
string[] StateF = new string[5];
string Sthelp = string.Empty;


public Form1()
{
InitializeComponent();
}


private void Enterbtn_Click(object sender, EventArgs e)
{
Parallel.For(0, 5, j =>
{
//MessageBox.Show("j is :" + j);
Tagging(j);
});




for (int PairNumber = 0; PairNumber < 5; PairNumber++)
{
Sthelp = Sthelp + " *** StateF[" + PairNumber + "] is : " + StateF[PairNumber].ToString() + " *** \n";


Outputtxt.Text = Sthelp;
}


}
private void Tagging(int PairNumber)
{


Random R = new Random();


int Random1;
Random1 = R.Next(0, 100000);
// یک عدد تصادفی تولید می شود
if ((Random1 % 2 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "L";
if ((Random1 % 3 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "G";
else StateF[(PairNumber)] = "S";
}
}
}



فرممان هم یک دگمه enter و یک تکست باکس برای چاپ خروجی دارد.
اگر مسیج باکس را حذف بفرمایید می بینید که همه خروجی هامون تکراری می شوند !!!

ژیار رحیمی
پنج شنبه 02 دی 1395, 21:23 عصر
شما قبل از نوشتن کدهای تست ،وموضوع های پردازش موازی و Concurency در سی شارپ را مطالعه نمایید.مشکل کد شما اینه که حلقه for بصورت Parallel بسته بازه حلقه for از دو Thread یا بیشتر در کنار MainThread اجرا میشود و قبل از اتمام حلقه for موازی حلقه پایین ان اجرا شده و در نتایج خروجی دچار مشکل میشود. دلیل اینکه با MessageBox نتیجه شما درست است اینه که خود Dialog مسیج باکس یک وقفه در MainThread میشود که حلقه for (پر کردن آرایه ) بعد از اتمام حلقه بالایی آن اجرا شود.برای حل من از Task برای دو حلقه for که حتما پشت سرهم شوند استفاده کردم.

string[] StateF = new string[5];
string Sthelp = string.Empty;
private void button1_Click(object sender, EventArgs e)
{
string Sthelp = string.Empty;
Task.Factory.StartNew(()=>
Parallel.For(0, 5, j =>
{
//MessageBox.Show("j is :" + j);
Tagging(j);
})).ContinueWith(t=>PrintOutPut());
}


private void PrintOutPut()
{
for (int PairNumber = 0; PairNumber < 5; PairNumber++)
Sthelp = Sthelp + " *** StateF[" + PairNumber + "] is : " + StateF[PairNumber].ToString() + " *** \n";
Outputtxt.Invoke((MethodInvoker)(() =>{Outputtxt.Text = Sthelp; }));
}


private void Tagging(int PairNumber)


{
Random R = new Random();
int Random1;
Random1 = R.Next(0, 100000);
// یک عدد تصادفی تولید می شود
if ((Random1 % 2 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "L";
if ((Random1 % 3 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "G";
else StateF[(PairNumber)] = "S";
}

ad hoc
جمعه 03 دی 1395, 12:16 عصر
خیلی متشکرم بابت تحلیل خوب و توضیحات مفیدتان.

حتما مطالعه می کنم .

منتهی با اجرای کد جنابعالی ، مساله ام حل نشد و این مشکل همچنان وجود دارد .

بعبارت دیگر در یک آرایه 3 خانه ای [StateF[2]،StateF[1] ،StateF[0 برچسب های تکراری چاپ می شود مثل S S S یا G G G و این تصادفی نیست .

بنابه توصیه جنابعالی ، من در حال حاضر مشغول مطالعه روی موازی سازی و استفاده از Task ها هستم ولی ممنون می شوم چنانچه موفق به حل این مساله شدید ، من را هم در جریان قرار بدهید.

با سپاس :لبخندساده:

ژیار رحیمی
جمعه 03 دی 1395, 14:45 عصر
مشکل از Parallel.For و Task ها نیست دلیل مشکل با هر بار فراخوانی تابع PrintOutPut هر بارنمونه سازی جدیدی از کلاس Random داخل تابع ایجاد میشود. دلیل تکراری بودن مقادیر هست.برای حل تعریف و نمونه سازی را خارج از تابع PrintOutPut قرار دهید.اصلاحیه پست قبلی به صورت زیر

Random R = new Random();
string[] StateF = new string[5];
string Sthelp = string.Empty;
private void button1_Click(object sender, EventArgs e)
{
Sthelp = string.Empty;
Task.Factory.StartNew(()=>
Parallel.For(0, 5, j =>
{
Tagging(j);
})).ContinueWith(t=>PrintOutPut());
}


private void PrintOutPut()
{
for (int PairNumber = 0; PairNumber < 5; PairNumber++)
Sthelp = Sthelp + " *** StateF[" + PairNumber + "] is : " + StateF[PairNumber].ToString() + " *** \n";
Outputtxt.Invoke((MethodInvoker)(() =>{Outputtxt.Text = Sthelp; }));
}


private void Tagging(int PairNumber)


{
var Random1 = R.Next(0, 100000);
// یک عدد تصادفی تولید می شود
if ((Random1 % 2 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "L";
if ((Random1 % 3 == 0) || (Random1 % 5 == 0)) StateF[(PairNumber)] = "G";
else StateF[(PairNumber)] = "S";
}

ad hoc
جمعه 03 دی 1395, 22:18 عصر
درسته جای () Random R = new Random اشتباه بود .:تشویق:

متوجه شدم .
دستتان درد نکنه . خــــــیلی ممنون .