هذا الموضوع يشرح موضوع تعدد المسارات فى الفيجوال بيسك دوت نت بالامثله العملية
Understanding Multi-Threading in VB.Net
فهم تعدد المسارات فى
الفيجوال بيسك دوت نت
لفهم ما هو تعدد المسارات يجب اولا
ان نفهم ما يحدث عند تشغيل البرنامج حيث يقوم نظام التشغيل بتحميل البرنامج فى
الذاكرة ويقوم البروسيسور بتنفيذ الاكواد سطر بسطر وعند النظر لهذا المثال نجد انه
سوف يتم تشغيل البرنامج وينتهى الامر ولكن عند فتح برنامج مثل notepad لا يتم الانتهاء من الاكواد
حيث يوجد بداخل البرنامج loop كبيرة تقوم بالتنفيذ بشكل لا
نهائى وتتحقق من مدخلات المستخدم وتقوم بتنفيذ تعليماته وعند الانتهاء من التنفيذ تعود لل loop مرة اخرى
فكر فى الكود السابق مثل الكود
التالى
Public Sub Main()
Do
Dim msg As MESSAGE = GetMessage()
If msg IsNot Nothing Then
ProcessMessage(msg)
End If
Loop
End Sub
ال loop تقوم بالتحقق من الرسالة
وعندما تجد رسالة تقوم بتمريرها لاجراء لعمل بعض العمليات عليها ولكن ماذا يحث لو
ان الاجراء به loop اخر والذى سياخذ بعض الثوانى او الدقائق
للتنفيذ
مثال :-
عند محاولة
تحميل ملف من الانترنت اكسبلورر تخيل ان الكود التالى هوالكود الخاص بتحميل الملف
Public Sub DownloadFile(ByVal url As String)
Dim fileSize As Integer = GetFileSize(url)
Dim fileName As String = GetFileName(url)
Dim curPos As Integer = 0
Do While curPos < fileSize
Dim fileData() As Byte
Dim bytesRecd As Integer = GetNextChunk(fileData)
curPos += bytesRecd
appendToFile(fileName, fileData)
Loop
End Sub
هذا ليس الكود الصحيح لتحميل ملف من الانترنت ولكن المفهوم سيكون مشابه له ولكن تخيل انه هو ماذا
سوف يحدث ؟ الاجراء DownloadFile به loop والتى
ستقوم بالتكرار لتحميل اجزاء الملف لذلك لو ان هذا الملف حجمه كبير سيتم تنفيذ هذا
الاجراء لكثير من الوقت والانترنت اكسبلورر لن يقوم بتنفيذ اى اجراءات حتى يتم
تحميل الملف بالكامل هذا معناه ان الانترنت اكسبلورر سيتوقف ولن يستجيب حتى الانتهاء من التحميل
اذن => ما هو تعدد المسارات
كثير منكم سوف يقول انه عندما يقوم بتحميل احد الملفات من المتصفح
يظل المتصفح يعمل بينما يتم تحميل الملف هذا يتم عن طريق تعدد المسارات فعندما
يكون هناك تحميل هذا التحميل يتم التعامل معه من خلال المسار الخاص به والمتصفح
يعمل مع مسار اخر وكل منهما يعمل مستقل عن الاخر
كيف يعمل تعدد المسارات
سنبداً بمثال
بسيط الاول سنقوم باستخدام حلقة loop
والتى تعد من 1 الى 100 لمحاكات عملية كبيرة مثل تحميل ملف
قم بفتح مشروع جديد وضع زر وليبل فى
الفورم وفى حدث الضغط على الزر ضع الكود التالى :
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For i = 1 To 100
Label1.Text = CStr(i)
Threading.Thread.Sleep(200)
Next
End Sub
نفذ البرنامج
واضغط على الزر ستجد ان البرنامج يتجمد حتى يتم الانتهاء من العد ولاحظ انه لا
يتم تحديث الليبل لماذا يحدث ذلك عند الضغط على الزر يتم تنفيذ العداد لذلك فى هذه
الاثناء تحديث العنوان الليبل لا يمكن تنفيذه ولا يمكن تنفيذ اى امر اخر حتى
الانتهاء من الامر السابق ولا يمكن حتى تحريك الفورم من مكانه
الحل هنا هو
تمرير العداد الى مسار اخر لتنفيذه
نبداً اولا بوضع الحلقة فى اجراء مستقل
Private Sub Count(ByVal Max As Integer)
For i = 1 To Max
Label1.Text = CStr(i)
Threading.Thread.Sleep(200)
Next
End Sub
الان لدينا العداد داخل اجراء خاص به وفى حدث
الضغط على الزر نكتب الكود التالى
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.Start(100)
End Sub
السطر الاول
يقوم بعمل مسار جديد thread وتمرير الاجراء المراد تنفيذه
عند طريق AddressOf لكن من المهم هنا ان نعرف انه غير مسموح الا باجراء له وسيط واحد فقط
السطر
الثانى يبدأ المسار ويأخذ وسيط واحد الخاص بالاجراء
ملاحظة
لو لديك اختيار Option Strict On اضف هذا الا جراء
Private Sub Count(ByVal Max As Object)
If TypeOf Max Is Integer Then
Count(CInt(Max))
End If
End Sub
والسبب وراء
اضافة هذا الاجراء لان المشيد الخاص بالمسار يتوقع اجراء ياخذ وسيط واحد واختيار option strict لن يسمح لان يتم تمرير وسيط من نوع integer الان نفذ البرنامج
الان سيظهر الخطأ التالى
والان ما معنى الخطا الظاهر وما
سببه , هذا الخطا ظهر ليمنع كارثه محتمله تذكر ان ال UI له المسار الخاص به و ال UI هو كل ما تراه امامك فى الفورم الزر والليبل
وكل الادوات التى تضعها مسئول عنها UI ومسئول عن كل الاحداث الخاص
بهم ولذلك فهو يقوم بمنع اى مسار اخر بالتحكم فى هذه الادوات والا سوف يسبب ذلك
عدم ثبات فى البرنامج ولذلك يقوم الفيجوال بيسك بمنع تغيير الليبل من مسار اخر .
الطريقة الصحيحة
لعمل ذلك هو طلب من ال UI تعديل الليبل ولو ان هناك اوامر اخرى جارى تنفيذها عند الطلب سيتم
جدولة هذا الطلب حتى يتم الانتهاء من الاعمال المسندة اليه ويقوم بتحديث الليبل
كيف يمكن عمل هذا الطلب ...
نقوم بعمل الاجراء التالى لتغيير
الليبل
Private Sub SetLabelText(ByVal text As String)
If Label1.InvokeRequired Then
Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)
Else
Label1.Text = text
End If
End Sub
فى هذا الاجراء
تم طلب الخاصية InvokeRequired لل label لتحديد هل يتم استخدام الليبل
من المسار الحالى لل UI ام مسار
خارجى ويعطى القيمة true فى حالة لو
انه مسار خارجى
Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)
السطر السابق
يقوم بتنفيذ الطلب لل UI لتغيير الليبل عن طريق الاجراء
SetLabelText ولكن بدلا
من التنفيذ على المسار الاخر بدلاً من ذلك سيتم تنفيذه على المسار الخاص بال UI
الخاصية InvokeRequired ستعيد القيمة False والتى ستنفذ
عملية تغيير قيمة الليبل هذا هو المفتاح لان ال Ui thread سينفذ الاجراء فقط عندما لا
يكون مشغول بتنفيذ اجراءات اخرى
Private Sub Count(ByVal Max As Integer)
For i = 1 To Max
SetLabelText(CStr(i))
Threading.Thread.Sleep(200)
Next
End Sub
لقد قمنا
باستخدام SetLabelText لتغيير الليبل بدلا من محاولة تغييره مباشرة
الان نجحنا بانشاء تطبيق تعدد مسارات بسيط
شئ واحد باقى .
نفذ البرنامج واضغط على الزر واغلق الفورم قبل انتهاء Count لو قمت بعمل هذا ستلاحظ ان
البرنامج لم يتوقف فعلياً لان المسار لا زال يعمل .
عادة
نحتاج ان نجعل المسار يعمل بالخلفية background thread
للعمليات مثل هذه لان هذه المسارات يتم انهائها عندما يتم انهاء البرنامج وذلك يجب
عمل التعديلات التالية
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.IsBackground = True
t1.Start(100)
End Sub
هذه الطريقة الاساسية للتعامل مع تعدد المسارات
فى الفيجوال بيسك دوت نت ا
فيما بعد ان شاء الله سيتم شرح موضوع Thread
Pools
ليست هناك تعليقات:
اضافة تعليق