الثلاثاء، 4 يوليو 2017

تعدد المسارات فى الفيجوال بيسك دوت نت

هذا الموضوع يشرح موضوع تعدد المسارات فى الفيجوال بيسك دوت نت بالامثله العملية

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
 
 الملف المرفق به مشروع على ما تم شرحه 







ليست هناك تعليقات:

اضافة تعليق

جميع الحقوق محفوظة © 2019 الحقيبة البرمجية لمبرمجى VB.NET