PDA

View Full Version : حرفه ای: اجرای یک حلقه با استفاده از async



رامین مرادی
شنبه 08 دی 1397, 09:49 صبح
سلام دوستان عزیز.
یه قسمتی از برنامه م هست که حالت پیام رسان هست و داخل flowLayoutPanel یوز کنترلی که ایجاد کردم رو ادد میکنم. به دلیل کندی سرعت به پیشنهاد یکی از دوستان میخوام از async استفاده کنم. لینک زیر رو پیشنهاد دادن ولی نتونستم کاری بکنم.
https://docs.microsoft.com/en-us/ef/core/querying/async

من میخوام حلقه زیر رو داخل تابعی از نوع async اجرا کنم .ممنون میشم راهنماییم کنید.



for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId)
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
else
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
}




داده هام درون datatable هست اسمشم dt.

farhad_shiri_ex
شنبه 08 دی 1397, 11:33 صبح
سلام دوستان عزیز.
یه قسمتی از برنامه م هست که حالت پیام رسان هست و داخل flowLayoutPanel یوز کنترلی که ایجاد کردم رو ادد میکنم. به دلیل کندی سرعت به پیشنهاد یکی از دوستان میخوام از async استفاده کنم. لینک زیر رو پیشنهاد دادن ولی نتونستم کاری بکنم.
https://docs.microsoft.com/en-us/ef/core/querying/async

من میخوام حلقه زیر رو داخل تابعی از نوع async اجرا کنم .ممنون میشم راهنماییم کنید.



for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId)
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
else
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
}




داده هام درون datatable هست اسمشم dt.

اگر کل این حلقه درون یک تابع async اجرا کنید که اتفاقی نمی افته به این علت که شما باید کل حلقه را برای عملیات همزمانی بازنویسی کنید تا بتونید هر بخش را به صورت همزمان اجرا کنید!
این کد را امتحان کنید...
البته مطمن نیستم کامل درست باشه! ولی تقریبا باید همچنین کاری انجام بدید.
ونکته دیگه اینکه کلاس های Task و دستورات کلیدی async ,await با Linq خیلی خوب سازگارتر هستند معمولا...

private async MsText getMessage(){
MsText m = new MsText();

for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId){
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
}
else{
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
}
}
returm m;
}

private async void Message_Click(object sender, RoutedEventArgs e)
{

var messageBuildText = getMessage();
var msg = await messageBuildText;
flowLayoutPanel1.Controls.Add(msg);
flowLayoutPanel1.ScrollControlIntoView(msg);

}

رامین مرادی
شنبه 08 دی 1397, 12:53 عصر
اگر کل این حلقه درون یک تابع async اجرا کنید که اتفاقی نمی افته به این علت که شما باید کل حلقه را برای عملیات همزمانی بازنویسی کنید تا بتونید هر بخش را به صورت همزمان اجرا کنید!
این کد را امتحان کنید...
البته مطمن نیستم کامل درست باشه! ولی تقریبا باید همچنین کاری انجام بدید.
ونکته دیگه اینکه کلاس های Task و دستورات کلیدی async ,await با Linq خیلی خوب سازگارتر هستند معمولا...

private async MsText getMessage(){
MsText m = new MsText();

for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId){
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
}
else{
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
}
}
returm m;
}

private async void Message_Click(object sender, RoutedEventArgs e)
{

var messageBuildText = getMessage();
var msg = await messageBuildText;
flowLayoutPanel1.Controls.Add(msg);
flowLayoutPanel1.ScrollControlIntoView(msg);

}

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

farhad_shiri_ex
شنبه 08 دی 1397, 15:07 عصر
ممنون دوست عزیز.شرمنده من مبتدی هستم تو این مورد فقط موقع فراخوانی چجوری باید فراخوانی بکنم؟ چون من بعد از کلیک روی یکی از سلولو های گرید حلقه م اجرا میشد.من الان باید Message_Click رو داخل رویداد کلیک گرید صدا بزنم؟

بله می توانید تو کلیک یکی از سلول های گرید هم قراربدید!

رامین مرادی
یک شنبه 09 دی 1397, 08:50 صبح
متاسفانه همون نتیجه قبل و عین روش خودم بود سرعتش.

دوستان اگه نظر دیگه ای دارن جهت نشون دادن پیامها شبیه پیامرسان ها . الان از یوزر کنترل استفاده میکنم که سرعت بارگذاریش زیاده. حتی پیاممهای هر شخص به همدیگه سر جمع 30 تا هم نمیشه اما تا بارگذاری کامل حداقل 3 ثانیه طول میکشه.:ناراحت:

farhad_shiri_ex
یک شنبه 09 دی 1397, 09:54 صبح
متاسفانه همون نتیجه قبل و عین روش خودم بود سرعتش.

دوستان اگه نظر دیگه ای دارن جهت نشون دادن پیامها شبیه پیامرسان ها . الان از یوزر کنترل استفاده میکنم که سرعت بارگذاریش زیاده. حتی پیاممهای هر شخص به همدیگه سر جمع 30 تا هم نمیشه اما تا بارگذاری کامل حداقل 3 ثانیه طول میکشه.:ناراحت:

دوست عزیز! عرض کردم که تفکر برنامه نویسی همزمانی / موازی اینطور نیست که صرفا از چند نخ استفاده کنید! باید کل ماژولی که می خواهید همزمان کنید تغییر کنه!
لذا در صورت رعایت نکردن این تکنیکها نه تنها سرعت بهتر نمیشه در برخی موارد بدتر هم می تواند بشه!
برای اینکه سرعت بهتری داشته باشید!
بهتره از تکنیک تقسیم وظایف divide and conquer استفاده کنید یعنی حلقه اصلی for که دارید را هر بخش را به یک Task بدید و در انتها جواب هر بخش را باهم join کنید بدین ترتیب سرعت خیلی بهتر خواهد شد برای استفاده از این تکنیک می توانید از کتابخانه TPL ویا از کلاس Task / Join استفاده کنید.
من قبلا تو همین سایت برای ++C و Java نمونه هایی گذاشتم بد نیست اونها را هم ببنید برای سی شارپ هم نمونه سورس دارم الان دسترس ام نیست در اولین فرصت حتما همین جا براتون میذارم.
در ضمن سایت iostream.ir هم بد نیست یه نگاه بندازید!

barnamenevisjavan
یک شنبه 09 دی 1397, 13:28 عصر
متاسفانه همون نتیجه قبل و عین روش خودم بود سرعتش.

دوستان اگه نظر دیگه ای دارن جهت نشون دادن پیامها شبیه پیامرسان ها . الان از یوزر کنترل استفاده میکنم که سرعت بارگذاریش زیاده. حتی پیاممهای هر شخص به همدیگه سر جمع 30 تا هم نمیشه اما تا بارگذاری کامل حداقل 3 ثانیه طول میکشه.:ناراحت:
در صورت امکان پروژتون رو اپلود کنید تا اصلاح کنم براتون
به این صورت باید استفاده کنید البته روش های مختلفی میشه استفاده کرد
private async void InitialDataAsync()
{


var b = await Task.Run(async () => {
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId)
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
else
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
}




return await Something;
});
}

هرجا خواستین اجرا کنین کافیه تابع رو صدا بزنین InitialDataAsync
دقت کنید اگر بخواین به اشیا موجود روی فرم دسترسی داشته باشین این نکته رو مدنظر داشته باشین:
فرم شما روی ترد اصلی قرار داره
وقتی شما از Async/await استفاده میکنید در واقع دارین یه ترد دیگه ایجاد میکنین و اونجا کارتون رو انجام میدین برای همین فرم شما بدون مشکل اجرا میشه
حالا اگر بخاین از تابع async اشیایی که توی فرم هستن رو دسترسی داشته باشین (یعنی از ترد جدا به ترد اصلی) بصورت مستقیم نمیتونین کار کنین و با خطا مواجه میشین برای حل مشکل باید کدهایی که با اشیا در تعامل هستن رو داخل دیسپچر بنویسین تا از طریق اون به ترد اصلی هدایت بشین
به عنوان نمونه:
await Dispatcher.InvokeAsync(() => {
if (SchoolQuery.Any())
cmbEditBase.ItemsSource = SchoolQuery;


});


نمونه کامل تر:(البته کامل نکردم فقط یه قسمت رو اصلاح کردم)


private async void InitialDataAsync()
{


var b = await Task.Run(async () => {
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["Ferestandeh"].ToString() == AppSeetingClass.PersonnelId)
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), true, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());

await Dispatcher.InvokeAsync(() => {
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);


});


}
else
{
MsText m = new MsText();
m.setMessage(int.Parse(dt.Rows[i]["Id"].ToString()), dt.Rows[i]["Time"].ToString(), dt.Rows[i]["Date"].ToString(), dt.Rows[i]["Matn"].ToString(), dt.Rows[i]["PerName1"].ToString(), dt.Rows[i]["FileName"].ToString(), bool.Parse(dt.Rows[i]["Show"].ToString()), false, AppSeetingClass.PersonnelId, dt.Rows[i]["FileTitle"].ToString());
m.Margin = new System.Windows.Forms.Padding(100, 0, 0, 0);
flowLayoutPanel1.Controls.Add(m);
flowLayoutPanel1.ScrollControlIntoView(m);
}
}




return await Something;
});
}