دعم التقارير المرحلية والنتائج المتزايدة في .NET 4.0 "مكتبة المهام الموازية"
-
20-09-2019 - |
سؤال
وأنا أعلم ذلك مكتبة المهام الموازية لا يزال في مرحلة تجريبية ومن المحتمل أن يكون هناك موارد أقل متاحة ولكن من كل ما قرأته، تمنح المكتبة معاملة خاصة جدًا له جدولة المهام, معالجة الاستثناء و إلغاء.
لكني لا أجد أي إشارة إليها التقارير المرحلية و إرسال النتائج المتزايدة من المهام.يبدو أن هذين الأمرين مهمان للغاية بحيث لا يمكن تجاهلهما.هل يمكنك إلقاء بعض الضوء على كيفية التعامل مع هذه المهام في مكتبة المهام الموازية أو الرجوع إلى بعض المقالات التي تشرحها؟
المحلول
يقوم هذا المثال بتحديث شريط التقدم:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class SimpleProgressBar : Form
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.Run(new SimpleProgressBar());
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
int iterations = 100;
ProgressBar pb = new ProgressBar();
pb.Maximum = iterations;
pb.Dock = DockStyle.Fill;
Controls.Add(pb);
Task.ContinueWith(delegate
{
Parallel.For(0, iterations, i =>
{
Thread.SpinWait(50000000); // do work here
BeginInvoke((Action)delegate { pb.Value++; });
});
});
}
}
نصائح أخرى
هذه واحدة من أفضل نتائج البحث الخاصة بي ولا يوجد حتى الآن مثال للتقدم فيها Task Parallel Library
هنا...
لقد صادفت اليوم TPL لأنني أرغب في تطوير تطبيق جديد متعدد الخيوط ولكن بدون استخدام BackgroundWorker
(لأنني قرأت في مكان ما عن المهمة باستخدام رمز جميل من قبل)
أقوم بتجميع المثال من إجابة @Stephen Cleary، والرابط الخاص به معقد للغاية للبحث عن التقدم، وبعض مواقع الويب الأخرى.
هذا هو المثال البسيط للغاية لكيفية القيام بذلك تقدم و مكتمل مع طريقة آمنة لموضوع واجهة المستخدم:
TaskScheduler currentTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task<string>.Factory.StartNew(() =>
{
// loop for about 10s with 10ms step
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(10);
Task.Factory.StartNew(() =>
{
// this is a task created each time you want to update to the UI thread.
this.Text = i.ToString();
}, CancellationToken.None, TaskCreationOptions.None, currentTaskScheduler);
}
return "Finished!";
})
.ContinueWith(t =>
{
// this is a new task will be run after the main task complete!
this.Text += " " + t.Result;
}, currentTaskScheduler);
سيتم عرض الرمز من 1 إلى 1000 في 10s ثم إلحاق "الانتهاء!" سلسلة في شريط عنوان نموذج Windows.يمكنك أن ترى أن TaskScheduler هي الطريقة الصعبة لإنشاء تحديث آمن لمؤشر ترابط واجهة المستخدم لأنني أعتقد أن المهمة المجدولة للتشغيل على مؤشر الترابط الرئيسي.
لا يوجد دعم مدمج لهذا مثل ما يقدمه برنامج BackgroundWorker.
يمكنك استخدام SynchronizationContext مباشرة؛هناك فيديو ممتاز هنا: http://www.rocksolidknowledge.com/ScreenCasts.mvc/Watch?video=TasksAndThreadAffinity.wmv
يقوم المؤلف بتطوير حلين في هذا الفيديو:أحدهما يستخدم SynchronizationContext والآخر يستخدم استمرارية المهام.بالنسبة لمشكلتك، لن تعمل الاستمرارات، لكن نهج SynchronizationContext سيعمل بشكل جيد.
ملاحظة.إذا كنت تقوم بإنشاء تعليمات برمجية قابلة لإعادة الاستخدام، فعند التقاط SynchronizationContext.Current، يجب عليك اختبار القيمة الخالية و(إذا كانت فارغة) استخدام SynchronizationContext المنشأ افتراضيًا بدلاً من ذلك.
تحديث:لقد قمت بنشر رمز لهذا على مدونتي.الحل الخاص بي يعتمد في الواقع على أ Task
الذي تمت جدولته مرة أخرى إلى مؤشر ترابط واجهة المستخدم بواسطة a TaskScheduler
الذي يستخدم SynchronizationContext
تحته.على عكس الإجابة المقبولة، سيعمل هذا الحل مع كل من WPF وWindows Forms.
TPL ليس موجهًا بشكل خاص نحو دعم واجهة المستخدم، ويمكنك (لا يزال) استخدام BackgroundWorker لذلك.أما بالنسبة لإرسال أو معالجة النتائج المتوسطة، فهناك فئات تجميعية جديدة (ConcurrentQueue) لدعم ذلك.