الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

السلسة الذهبية في المواضيع العلمية

بدأه رغيد الطيب في 14 مايو 2005 · 13 رد · 6,531 مشاهدة · في قسم الدروس والمواضيع الهامة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلسة الذهبية في المواضيع العلمية [ لماذا يجب أن نعتني بفهم شفراتنا ؟ ]

بسم الله الرحمن الرحيم

السلام عليكم و رحمة الله وبركاته

مرة أخرى نعود مع سلسلتنا العتيقة [ السلسلة الذهبية في المواضيع العلمية ] ليس بموضوع جديد بل إستكمالاً و تعزيزاً لموضوع سبق و الذي كان بعنوان ( كيف تحل مشاكلك بنفسك ؟ ) .. فقد عبر لي البعض عن رغبتهم بالمزيد من الامثلة تحفيزاً للقدرات وشحناً للهمم .. و ربما كان من الافضل في رأيي لو غيرنا الموضوع قليلاً تعميماً للفائده بإذن الله تعالى

موضوعنا اليوم ينصب في التعمق في بعض الحلول البرمجية و المقارنة بين الشفرات وتحسين الإداء العام لإكوادنا مع مراعة الفهم العميق للفروقات بين الشفرات و سنحاول تسليط الضوء بشكل لن اقول مفصلاً بالكامل و لكني سأقول مفصلاً بقدر إعانه الله لنا سبحانه و تعالى على العديد من الأمثلة البسيطة ...

مشكلة عدم توفر المعلومة و توظيف الخبرات

في ايامنا هذه اصبح غريبا ان يقول المرء ان المعلومة غير متوفر لديه بالشكل الكامل او ان هناك نقصاً في الموراد المعلوماتية خاصة مع نعمة الله الذي منّ بها على عباده في ايامنا هذه وهي ( الإنترنت ) ... لهذا فالمشكلة دائماً تكون في عدم اتاحة المجال للعقل البشري لمحاولة الإسترسال في استحظار الحلول و تعويده على شيء من الكسل و حب الإجابات السريعة و التي لا يوجد لها ما يبررها ( إلا إن كان المرء مقيداً بإتمام عمله في فترة زمنية معينة شارفت على الإنقضاء ) اما ما سوى ذلك فمن الجميل ان نستبدل كلمتنا المشهورة التي نستخدمها عند كل مشكلة برمجية ( لا أعرف الحل ! ) فنجعلها ( سأحاول أن اوجد حلاً ) ... بتغييرك الطفيف للكلمات السابقة يجعل باب الامل ينفتح من جديد و نعطي الفرصة لرؤوسنا كي تجرب حظها في إبتكار حلول قد تكون جميلة وقد تكون فظيعة (بائسة) غير ان الرائع بالتأكيد هو مجرد المحاولة ... دعونا نضرب مثالاً.

لنفرض مثلاً انني احتجت في أحد برامجي الى معرفة إسم او نوع النظام الذي يعمل عليه برنامجي ( Windows 95,98,Me,NT,2000, XP ) كي اقوم بأشياء معينة تترتب على نوع النظام ...

لتأدية هذا الأمر ينبغي عليك ان تحيط علماً ببعض دوال الـ API كي تعرف نظامك المستخدم وقد تكون شفرتك كالتالي :

Private Declare Function GetVersionExA Lib "kernel32" (lpVersionInformation As OSVERSIONINFO) As Integer

Private Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type

Function WindowsName() As String
    Dim OS As OSVERSIONINFO
    
    OS.dwOSVersionInfoSize = Len(OS)
    OS.szCSDVersion = Space(128)
    Call GetVersionExA(OS)
    
    If OS.dwPlatformId = 1 Then         ' 95,98 Or Me
       Select Case OS.dwMinorVersion
        Case 0:  WindowsName = "Windows 95"
        Case 10: WindowsName = "Windows 98"
        Case 90: WindowsName = "Windows Me"
       End Select
    
    ElseIf OS.dwPlatformId = 2 Then    ' NT,2000 Or XP
       Select Case OS.dwMajorVersion
        Case 3: WindowsName = "Windows NT 3.51"
        Case 4: WindowsName = "Windows NT 4.0"
        Case 5: WindowsName = IIf(OS.dwMinorVersion, "Windows XP", "Windows 2000")
       End Select
    End If
    
End Function

في شفرتنا السابقة استخدمت انا دالة الـ API الخاصة بهذا الأمر وهي GetVersionExA و بالتالي فإن الكود سيعمل بإذن الله تعالى .. و لكن اذا صادف اننا لم نكن نعلم بهذه الدالة الخاصة بهذا العمل فهنا ينبغي علي محاولة الإستنتاج المنطقي للحل.

يعني دعونا نحاول القيام بالسابق بشكل مختلف و بالتالي فإن طريقة تفكيرنا في الحل لابد و ان تختلف قليلاً .. و إن ركزنا قليلاً سنجد ان الوينذوز طالما احتفظ ببياناته في مسجل النظام او الـ Registry و بالتالي فإننا لو اعرناه شيئاً من الإهتمام لعرفنا ان هناك مفاتيح في الريجستري تحتوي على إسم نظام التشغيل و بالتالي يمكن بسهوله ان نقوم بإستغلال ذلك في حل مشكلتنا السابقة

فبعلمنا ان الوينذوز يتحفظ بإسمه ( اسم نظام التشغيل ) في احد مفتاحين اما المفتاح :

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProductName

في حالة الانظمة 95 او 98 او ME ... او في المفتاح :

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName

في حالة احد الانظمة NT, 2000, XP وبالتالي ينبغي مراعه ذلك في تصميمنا للحل ... و يمكن اقتراح الحل التالي :

Function WinRegistry() As String
    Dim Shl As Object
    
    On Error Resume Next
    
    Set Shl = CreateObject("WScript.Shell")
    
    WinRegistry = Shl.regRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\" & _
                    "Windows\CurrentVersion\ProductName")
    
    If Err.Number <> 0 Then
        WinRegistry = Shl.regRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\" & _
                        "Windows NT\CurrentVersion\ProductName")
    End If
End Function

حيث تقوم الدالة السابقة بمحاولة القراءة من المفتاح الأول ( الخاص بالانظمة 95, 98, ME ) فإن حصل أي خطاء اي فان الـ Err.Number يحتفظ بقيمة الخطأ الذي حصل في الكود و بالتالي فان لم تكن القيمة هذه تساوي صفراً ( اي انه يوجد خطأ ) فمن الطبيعي عندها معرفة ان هذا المفتاح الذي حاولنا قرأته غير موجود اصلاً و بالتالي يمكن محاولة قرأة المفتاح الآخر وهو ما تقوم به الدالة السابقة.

ما ينبغي التركيز عليه اننا حتى و ان لم نكن نعرف دالة الـ API المسماه GetVersionExA فقد استطعنا بعون الله تعالى ان نوظف معلومتنا البسيطة عن الريجستري لحل الموضوع ..

و لكن دعنا نكون اكثر تشاؤماً و نفترض انه حتى تلك المعلومة عن الريجستري لم تكن بحوزتنا فما الذي ينبغي علينا القيام به للخروج من المأزق و الحصول على اسم نظام التشغيل ؟!!

عند هذه النقطة ينبغي ان نتوقف قليلاً و نشرب كوباً من الشاي مع الإستمرار بتقليب الامور في رؤوسنا عل الله ان يفتح علينا بشيء آخر جديد ...

نعم قد يخطر في بال احدنا ان نستفيد من تقنية الـ WMI إختصاراً لـ Windows Management Instrumentation و هي عبارة عن مجموعة من الفئات التي يمكنك بواسطتها معرفة الكثير من المعلومات عن نظامك الحالي او أي انظمة اخرى يمكن الوصول اليها عن طريق الشبكة مع توفر الصلاحيات اللازمة لذلك ... و يهمنا في هذا الأمر هو الفئة المسماه Win32_OperatingSystem ومن إسمها يمكن التنبؤ بانها تختص بمعلومات عن نظام التشغيل و بهذا يمكن ان نستخدم هذه في دالة بسيطة ننشئها قد تكون كالتالي :

Function WinWMI() As String
    Dim WMI, System As Object
    
    Set WMI = GetObject("WinMgmts://localhost").InstancesOf("Win32_OperatingSystem")
    
    For Each System In WMI
        WinWMI = System.Caption
        Exit Function
    Next
End Function

وبهذا نكون قد إستخدمنا طريقة اخرى مفيدة لحل هذه المسئلة البسيطة بحمد الله وتوفيقه سبحانه

لكن ما يشغلني الآن هل جميعنا يعرف هذه التقنية ( WMI ) اظن انه مهما بلغت درجة معرفتنا و إطلاعاتنا فلابد و أن شخص بيننا ينظر الى الكود السابق نظرته الاولى.

اذاً دعونا الآن نفترض اكثر الأمور سواءً حتى نخرج بفائدة واحدة ( مهما قلت درجة معرفتك فقط حــــــــــــــــــــــــاول ) و لنتخيل ان بيننا من ليست لديه أي إحاطة سوى بعلوماته عن نظام التشغيل DOS فقط ... بالطبع الى جانب معلوماته في الفيجوال بيسك ( لايمكن ابداً افتراض انه لايعرف الفيجوال ! لانه لن يكون قد كتب عنوان موقعنا هذا اصلاً و لم يكن ليصل الى هذه الصفحة التي نقرأها الآن ) ...

و بالتالي هل على شخص كهذا ان يفقد الامل نظراً لقدم معلوماته ( بالطبع لا ) ينبغي اولاً ان لا ييئس ابداً و ثانياً أن لا ينسى بأن يعمل تحديث لهذه المعلومات لاحقاً بإذن الله تعالى

المقصود هنا وعودة الى الوراء قليلاً و الى أيام الـ DOS فالكثيرين منا طالما استخدموا الامر Ver و المختص بمعرفة إصدار النظام المستعمل ... و بالتالي فما الذي يمنع استخدام هذا الامر من خلال الفيجوال بيسك لمعرف إسم الوينذوز !

طبعاً ليس هناك أي مانع بإذن الله تعالى و لكن ربما كان هناك عائق وهو ان اوامر الـ DOS تكتب مخرجاتها الى شاشة الدوز السوداء و بالتالي وجب معرفة كيفية استحظار هذه المعلومات الى برنامجنا ... و بما ان موضوعنا هذا غرضه الرئيسي هو الإستفادة بشتى الطرق فلا يوجد ما يمنع ان نحيد عنه قليلاً و نحدث ببضعه سطور عن كيفية توجيه المخرجات في الدوز

اذا قمت مثلاً بكتابة الامر التالي في شاشة الدوز :

Dir

فان المخرجات ستكون هي اسماء و بعض المعلومات عن الملفات و المجلدات في المجلد الحالي وجميع هذه البيانات يتم عرضها في الشاشة السوداء و لكننا اذا اردنا توجيه هذه المخرجات الى هذف معين ( لنقل ملف نصي اسمه data.txt ) فمن المفروض عندها ان نكتب التالي :

Dir >> c:\data.txt

بعد تنفيذك للأمر السابق فانك ستلاحظ ان النظام قد انشىء لك ملف على المسار C:\data.txt و فيه جميع البيانات التي كان ينبغي ان تعرض على الشاشة غير انها تم عرضها داخل الملف المذكور

و بالتالي ففي حالتنا نحن يمكن ان نستخدم الأمر ver بنفس الطريقة بحيث نقوم بتوجيه المخرجات الى ملف نصي مؤقت ثم نقوم باستخراج البيانات من داخل الملف الى داخل برنامجنا .. يعني في جهازي مثلاً اذا قمت بطباعة الامر VER في شاشة الدوز فاني النتاج هو :

Microsoft Windows XP [Version 5.1.2600]

و اذا استخدمت مفهوم توجيه المخرجات بحيث اكتب السطر التالي :

ver >> c:\data.txt

في الدوز فان نفس العبارة السابقة سوف يتم تخزينها في الملف data.txt وهذا بيت القصيد ..

بقي ان نعرف ان الملفات التنفيذية المسئولة عن تشغيل اوامر الدوز هي الملفين Cmd و Command حيث انه يتم استخدام الامر Command في الانظمة 95 ,98 ,ME بينما الامر Cmd في انظمة الـ NT بحيث يمكن تنفيذ الامر الذي تريده عن طريق الدالة Shell

فمثلاً لتنفيذ الامر Dir من داخل الفيجوال بيسك قم بالتالي :

Shell "Cmd /c Dir",vbNormalFocus

او بالطبع في الانظمة الاخرى

Shell "Command /c Dir",vbNormalFocus

واذا اردنا توجيه المخرجات للامر بحيث تصب في ملف نصي يمكن ان نكتب التالي :

Shell "Cmd /c Dir>>c:\data.txt", vbNormalFocus
او
Shell "Command /c Dir>>c:\data.txt", vbNormalFocus

ولكي لا نزعج المستخدم بظهور الشاشة امامه بحيث يتم تنفيذ العمل دون علمه يمكن اخفاء شاشة الدوز بالشكل التالي :

Shell "Command /c Dir>>c:\data.txt", vbHide
او 
Shell "Cmd /c Dir>>c:\data.txt", vbHide

اذا الحل المقترح هنا هو ان نقوم باستخدام الامر ver مع توجيه المخرجات الى ملف نصي ثم فتح هذا الملف النصي و استخراج البيانات منه يلي ذلك القيام بحذف الملف بعد قرأه محتوياته و عرضها اخيراً على المستخدم الذي لن يعلم بما كان يدور في الخفاء ... و الشفرة التي اقترحها مثل :

Function WinDOS() As String
    Dim X As Long, S As String
    
    On Error Resume Next
    
    If Dir("C:\Ver.txt") <> "" Then Kill "C:\Ver.txt"

    Call Shell("Cmd /c VER>>C:\Ver.txt", vbHide)
    If Err.Number <> 0 Then Call Shell("Command.Com /c VER>>C:\Ver.txt", vbHide)
    
Wait:
    Do
        DoEvents
    Loop Until Len(Dir("C:\Ver.txt"))
    DoEvents
    
    X = FreeFile
    Open "C:\Ver.txt" For Input As X
    Line Input #X, S
    Line Input #X, S
    Close X
    
    If S = "" Then GoTo Wait
    
    Kill "C:\Ver.txt"
    WinDOS = Left$(S, InStr(S, "[") - 1)
End Function

سوف انهي هنا هذا المثال الطويــــــــــــــــــــــــــــــــــــــــــــــل على أمل ان لايكون الملل قد تسرب الى نفس القارىء و اكتفي بالقول حبذا لو استغل كلاً منا معلوماته مهما قلت في البحث عن الحل ثم لابأس بعد ذلك ان يستعين بأي احد عند انقطاع الحيلة

ايهما افضل الاكواد الطويلة او الشفرات القصيرة التي تؤدي نفس العمل

يخطىء الكثير في تقييم الكود عن طريق عدد السطور المستخدمة خاصة اذا كانت المخرجات واحدة ! ... حيث ان كفاءة الكود تقاس دائماً بالزمن المستغرق و اداء الكود و استخدامه لموارد النظام و الإحاطة بكافة الإحتمالات المتوقعة والكثير الكثير من التفاصيل و يأتي اخيراً عدد السطور اذا تساوت جميع النقاط السابقة .. فمثلا في مثالنا السابق وضعنا سوياً اربعة حلول قد تكون جميلة و لكن اذا اردنا التقييم فمن افضلها ؟!

في الواقع ان الافضل هو الكود الاول نتيجة انه يستخدم دالة الـ API التي تم تعريفها في الملف kernel32.dll وهو احد الملفات الرئيسية التي يعتمد عليها الوينذوز و بالتالي فانك تضمن توفرها في جميع الانظمة ضمنياً اي ان شفرتك ستعمل بإذن الله في اغلب الاحوال !

الحل الثاني و المعتمد على الريجستري في الواقع هو حل ظريف ايضاً غير انه يعتمد على على قيمة موجودة في الريجستري و نعلم ان تغيير قيم الريجستري هو امر هين سواءً بالكود او يدوياً فلو ان احدهم عدل القيمة الموجودة في الريجستري بحيث تصبح "arabTeam2000 Operating System" فانك سوف تجد ان الدالة تعيد لك قيمة مفادها ان نظام الوينذوز المستخدم لديك هو نظام تشغيل الفريق العربي !! ( مبارك النظام الجديد شباب ) ... وهذا و إن كان شيئاً نادراً حدوثه ان يقوم احدهم بتعديل هذه القيمة و لكنه ايضاً سبب وجيه في فشل الدالة في عملها و بالتالي فانه احد عيوب الدالة

الحل الثالث يعتبر الاول من حيث عدد السطور البرمجية القليلة ( و التي ليست مقياس كما اتفقنا سابقاً ) و لكنه سيء جداً من ناحية الموثوقية و ذلك ان تقنية الـ WMI هي تقنية ضمنية موجودة في الانظمة ME, NT, 2000, XP غير انها ليست كذلك في الانظمة 98 و 95 و ينبغي ان يتم تحميلها اولاً على النظام حتى تعمل شفرتنا بشكل سليم ! ... و بهذا فان هذا العيب القاتل يضيف نقطة سوداء كبيرة الى تقييمنا لهذا الحل

و اخيراً الاجابة الاقدم و الاخيرة ( الاعتماد على الامر Ver في الـ DOS ) وهي اجابة تعمل بشكل جيد على الرغم من كونها ليست عملية كفاية من حيث اعتمادها برامج خارجية حيث ان الامر Shell يشغل برامج خارج نطاق الفيجوال بيسك و بالتالي فالكثير من الاخطاء يمكن حدوثها خارج الفيجوال بيسك قد تؤدي الى فشل العملية منها مثل عدم امكانية الكتابة الى القرص الصلب لأي سبب من الاسباب او أي خطأ غير متوقع يعيق إنشاء الملف المؤقت الذي قمنا بتوجيه مخرجات الامر Ver اليه سيؤدي بالتالي الى فشل دالتنا .. كما انه من غير المستحب ابداً اعتماد شفراتك على اوامر بهذا القدم ( الامر Ver ) فلا يعلم احدنا الى أي مدى سيبقى دعم هذا الامر موجوداً .. فربما ثم التخلي عنه في وقت قريب و الله سبحانه و تعالى اعلى و اعلم !

الى اي مدى يفيدنا تحليل الشفرات

لا اظن ان بيننا من يقول انه من غير المجدي ان يتم دراسة شفرتنا وتحليلها للوصول الى افضل طريقة ولكن الذي يختلف من شخص الى آخر هو تقدير اهمية القيام بذلك .... فلو انه تم طلب تصميم برنامج من احدنا فأنه يسعى بالمقام الاول ان ينتج اكوادا تقوم بالمطلوب منها و لكن كثيراً ما يتم إغفال عملية التأكد من كون هذه الاكواد التي طلبناها هي افضل اكود تقوم بذلك !

دعونا نتسلى بمثال بسيط ... فلكي نملىء قائمة ( ListBox ) بعناصر كثيرة ( لنقل 25000 ) عنصر فاننا سوف نكتب كود كالتالي :

    Dim I As Long

    For I = 1 To 25000
        List1.AddItem I
    Next

فإن هذه العملية هي عملية بسيطة ولكنها تأخد وقت طويل حيث ان جهازي ( الذي هو بمواصفات 256MB رام .. و معالج بسرعة 800MHz ) فقد استغرقت عملية ملىء القائمة بـ 25000 عنصر وقت مقداره ( 9 ثواني كاملة ! ) ... وهو رقم مهول للغاية فمن أين لك بمستخدم لبرنامجك ( في هذا الزمان السريع للغاية ) يمتلك طول بال لهذا الحد !

و لكي تختبر سرعة الكود السابق في برنامجك عدل الكود كالتالي :

    Dim I As Long
    Dim T As Single
    
    T = Timer
    
    For I = 1 To 25000
        List1.AddItem I
    Next
    
    MsgBox Round(Timer - T)

و الان كيف يمكننا ان نحسن الكود السابق بحيث نقتصد في وقت مستخدم برنامجنا ( و نقنعه بعدم رمي البرنامج في سلة المحذوفات بعد اول إستخدام ) .... في الواقع إن القيام بذلك يتم بفهم عمل مربع القائمة جيداً ! ... فلو انك اضفت السطرين التالين الى البرنامج :

    Dim I As Long
    Dim T As Single
    
    T = Timer
    List1.Visible = False
    
    For I = 1 To 25000
        List1.AddItem I
    Next
    
    List1.Visible = True
    MsgBox Round(Timer - T, 1)

السطران الذي اضفناهما ( List1.Visible = False & List1.Visible = True ) جعلا الزمن المتطلب لملىء القائمة ينخفض من 9 ثواني إلى أقل من ثانية واحدة !

و السبب هنا يعود الى عمليات التحديث ... إذ انه بعد كل عملية إضافة بإستخدام AddItem فإن مربع القائمة يقوم بتحديث نفسه ( Refersh ) بحيث يظهر العنصر الجديد وايضاً لتغيير طول شريط التمرير ( Scroll Bar ) مع إزدياد طول القائمة ..... و هذا كله يحتاج الى وقت فليس من الهين ان تقوم بـ 25000 علمية تحديث امام عيني المستخدم ... و بالتالي فإنه بجعل القيمة Visible تساوي False قبل الإضافة الى القائمة و ارجاعها الى True بعد الإنتهاء يقوم بإخفاء القائمة و بالتالي فلن يضطر الفيجوال بيسك الى إعادة تحديث القائمة إلا مرة واحدة فقط عندما نقوم بإظهار القائمة مرة أخرى عن طريق Visible = True ...

يظهر بوضوح ان ابسط التعديلات في الكود قد تؤدي الى نتائج غير متوقعة على اداء البرامج التي نصممها

ولو ان في نفسك شيئاً من حب الإستزادة من الامثلة دعني و إياك نجرب المثال التالي :

لو اننا احتجنا الى تكوين دالة بسيطة تقوم بعمل سلسلة نصية مكونة من اسم شخص متبوعاً برقم متسلسل لعدد كبير من المرات ( لنقل 25000 مرة ) يعني مثلاً :

Rgheed1,Rgheed2,Rgheed3,.....,Rgheed24999,Rgheed25000

و لتنفيذ هذه المهمة البسيطة للغاية يمكن إستخدام كود كالتالي :

    Dim I As Long
    Dim T As Single
    Dim S As String
    
    T = Timer
    
    For I = 1 To 25000
        S = S & "Rgheed" & I & ","
    Next
    
    MsgBox Round(Timer - T, 1)

وهو كود جميل و بسيط وقام بالمطلوب منه بشكل جيد و نتج عنه متغير S فيه سلسلة حرفية تحتوي على النص المطلوب تماماً ... و لكن الشيء المقزز فعلاً هو الوقت الذي استغرقته لدالة السابقة للقيام بهذه المهمة حيث أنه وبإستخدام جهازي نفسه ( ذي المواصفات المذكورة اعلاه ) كان الوقت المستهلك هو 138 ثانية ( أي ما يزيد عن الدقيقتين بقليل ! ) وهو زمن اقل ما يمكن ان يوصف به هو ( فضيـــــــــــــــــــــــــــــــــــــــــــــع ) و لا اخفيك أني هممت أن اقوم بإيقاف البرنامج قبل ان ينهي عمله نتيجة للمل الذي اصابني من انتظاره .

و إن كان الكود في المثال الذي سبق مثالنا الأخير قد استغرق 9 ثواني ( فقط ) ومع ذلك فلم نحتمله وقمنا بتحسينه ليصبح اقل من ثانية واحدة فإننا هنا ( يجب ) ان نحسن مثالنا هذا ولا ندعه بالصورة التي هو عليها الآن

و للقيام بذلك يمكن اتباع طرق مختلفة كلاً بحسب الطريقة التي سنفكر بها ... و دعني هنا اقترح و احدة و هي ان نعدل الكود قليلاً ليصبح :

    Dim I As Long
    Dim T As Single
    Dim S As String
    Dim Temp(1 To 25000) As String
    
    T = Timer
    
    For I = 1 To 25000
        Temp(I) = "Rgheed" & I
    Next
    
    S = Join(Temp, ",")
    
    MsgBox Round(Timer - T, 1)

الكود السابق لم يقم بتقليل وقت الإنتظار و لكن يمكنك القول بأنه ( قضى ) على الإنتظار و جعل الزمن الكلي لإداء العملية السابقة وللحصول على متغير يحتوي على تلك السلسلة هو اقل حتى من ربع ثانية او على وجه الدقة ( 0.1 من الثانية ! ) فأنت لا تكاد تشغل الكود حتى ينتهي من اداء عمله !

و ما قمت به هنا امر معروف منذ زمن طويل فهو تعديل بسيط للغاية سيفكر به كل من اعطى الامر لحظات من الإهتمام والتركيز للبحث عن تحسين مناسب .. ولكي نفهم الفرق بين الكودين ينبغي اولاً ان نعرف العمل الذي يقوم به الكود الأول

إذ انه يقوم بتعديل قيمة المتغير S لعدد 25000 مرة و هذا ليس سيئاً في المراحل الأولى التي يكون فيها حجم المتغير S صغيراً ولكنه يعتبر كارثه حقيقة عندما يزداد حجم المتغير تدريجاً إذ ان كل دورة من الدورات الـ 25000 تزيد حجمه بمقدار اقله 8 بايت ( وهو ناتج عن طول الكلمة Rgheed وهو 6 حروف بالاضافة الى طول الرقم الذي يليها واخيرا طول الفاصلة وهو 1 ) واقصى حجم للزيادة هو 12 بايت ... و بحسبة بسيطة يظهر لنا ان طول المتغير يزداد من الصفر وحتى يصبح 282 كليوبايت ( او مايساوي 288894 بايت ) وهو عدد مهول للغاية اذا ما فهمنا انه سوف تتم معالجته لاكثر من عشرين ألف مرة ( 25000 ) . يعني بحسبة بسطية فأن الخمسة الف مرة الاخيرة من الدوران و اذا افترضنا ان حجم المتغير سيكون فيها متوسطاً حوالي 250 كليوبايت فانك ستجبر برنامج في الخمسة الف دورة الاخيرة على معالجة اكثر من 1.2 جيجا بايت من البيانات !! وهذا في اواخر الخمسة ألف دورة من الدورات الخمسة والعشرين ألف دورة !

لهذا جاءت فكرة الكود الثاني و التي تقوم اولاً بحجز مصفوفة نصية فيها 25000 عنصر بالشكل التالي :

Dim Temp( 1 To 25000) As String

ثم نقوم في كل دورة من الدورات بتعيين قيمة لأحد هذه العناصر ( من عناصر المصفوفة ) و بالتالي فهي جميعاً عناصر صغيرة جداً لايزيد حجم اكبرها عن الـ 11 بايت ... كما ان مقدار الذاكرة يتم حجزة مرة واحدة عند تعريف المصفوفة ... وبعد الإنتهاء من تعيين قيم العناصر جميعاً ... قمنا بتجميعها في متغير نصي واحد S عن طريق الدالة Join التي تقوم بالتجميع

و بالتالي فان التعامل مع الذاكرة في الحالة الثانية كان كفوءً للغاية بعكس الكود الأول الذي يقوم بتغيير حجم المتغير S لآلاف المرات مع الإزدياد الرهيب لحجم المتغير ...بينما اكتفت الطريقة الثانية بالتعامل مع المتغير S ذو الحجم الكبير مرة واحدة فقط ( عند التجميع ) بينما مرات الدوران الكثيرة كانت تتعامل مع متغيرات صغيرة جداً ( هي عناصر المصفوفة ) .

و بالتالي فقد تم اختصار ما يزيد عن الـ 137 ثانية وذلك بزيادة سطران فقط ! في الكود مع اختلاف طريقة تفكيرنا في الحل ... ولك ان تجرب تغيير عدد الدروات بدلاً من 25000 لترى الفروقات

خاتمة

اتمنى بالفعل ان نخرج من هذا المقال بحرص شديد على العناية اكثر بفهم اكوادنا البرمجية لتحسين اداءها بإذن الله تعالى

السلام عليكم و رحمة الله و بركاته

RgheedWinVer.zip

مواضيع برمجية تقنية جديدة

----------------------------------------------------------------------------------------------------------------------------------------------

• إستغلال خدمة الـ RSS في برامجنا ومواقعنا ! (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج للبحث في الملفات ومحتواياتها (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• فئة للتراسل بين برنامجين في جهاز واحد ! (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

مواضيع برمجية تقنية قديمة

----------------------------------------------------------------------------------------------------------------------------------------------

• إستغلال رسائل البالونات Balloons في الوينذوز أكس بي(VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• مقالة : لماذا يجب ان نعتني بشفرات برامجنا !؟- (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• لمطوري البرامج و مواقع الويب - برنامج تركيب ألوان - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج : بسيط للتحكم بالنظام, عن طريق الريجستري - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج : لتقييد و منع تشغيل البرامج الاخرى - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• النوافذ المنبثقة و طريقة لإستغلالها في برامجنا -(VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• تقنية الإستدعاء الذاتي - (VB.NET , VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• مصفوفات الأدوات Control Arrays افكار وتلميحات ! - (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• أفكار و تلميحات[ المعنى الحقيقي للـ True و False ] - أمثلة (VB.NETVB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• دوال الـ APIs و مايقابلها في الدوت نت ! - (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

#2

متشكر جداً أخى رغيد والله معلومات قيمه جداً :)

#3

متميز دائماَ بمواضيعك الجميلة

#4

بارك الله فيك أخي رغيد على هذه المعلومات الطيبة .. نسأل الله العلي القدير أن يجعلها في موازين حسناتك إنه ولي ذلك والقادر عليه ..

وأعجبني كثيراً مثالك المتعلق بالسلسلة النصية .. فلي تجربة معها ..

فقد عملت برنامج يستخدم قاعدة بيانات .. ومع مرور الأيام أردت عمل موقع على غرار البرنامج .. فأردت أخذ البيانات من البرنامج لكي أدخلها في قاعدة بيانات ( MYSQL ) وذلك بعمل ملف نصي يستخرج عبارات الـ ( SQL ) ومن ثم إدخالها إلى قاعدة البيانات ( MYSQL ) .. وكانت قاعدة البيانات تحتوي على أكثر من ( 50000 ) خمسين ألف حقل وأقل حقل يحتوي على 100 حرف .. وبعض الحقول تحتوي على 5000 حرف أو أكثر .. هذا بالإضافة إلى بيانات الحقول الأخرى ..

فكنت أفرغ بيانات المتغير النصي بعد كل 1000 حقل لتجنب البطء في البرنامج .. وفي النهاية يتكون لي ملفات SQL كثيرة .. وكان البرنامج يأخذ أكثر من نصف ساعة ( تخيييييييييل ) ثم فكرت بطريقة مختلفة تماماً .. فأصبحت أفرغ محتويات المتغير النصي بعد كل حقل وأضيفه إلى الملف .. فلم يستغرق البرنامج أكثر من ثواني معدودة ...

أكرر شكري لك أخي رغيد ..

#5

شكراً على المعلومات القيمة استاذى رغيد الطيب :rolleyes:

إن قلت قال الله قال رسولـه همزوك همز المنكر المتعالي
أو قلت قد قال الصحابة والألـى تبعاً لهم بالقول والأعمال
أو قلت قـال الشافعي وأحمد و أبو حنيفة والإمام الغالي
صدوا عن وحي الإله ودينـه واحتالوا على حرام الله بالإحلال
يا أمةً لعبت بدين نبيها كتلاعب الصبيان في الأوحال
حاشا رسول الله يحكم بالهوى تلك إذاً حكومة الضلال

feed.1.gif

#6

السلام عليكم و رحمة الله و بركاته

الحمد لله الذي سهل علي ايصال ما اردته فله الحمد سبحانه

السلام عليكم و رحمة الله وبركاته

مواضيع برمجية تقنية جديدة

----------------------------------------------------------------------------------------------------------------------------------------------

• إستغلال خدمة الـ RSS في برامجنا ومواقعنا ! (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج للبحث في الملفات ومحتواياتها (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• فئة للتراسل بين برنامجين في جهاز واحد ! (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

مواضيع برمجية تقنية قديمة

----------------------------------------------------------------------------------------------------------------------------------------------

• إستغلال رسائل البالونات Balloons في الوينذوز أكس بي(VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• مقالة : لماذا يجب ان نعتني بشفرات برامجنا !؟- (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• لمطوري البرامج و مواقع الويب - برنامج تركيب ألوان - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج : بسيط للتحكم بالنظام, عن طريق الريجستري - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• برنامج : لتقييد و منع تشغيل البرامج الاخرى - (VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• النوافذ المنبثقة و طريقة لإستغلالها في برامجنا -(VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• تقنية الإستدعاء الذاتي - (VB.NET , VB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• مصفوفات الأدوات Control Arrays افكار وتلميحات ! - (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

• أفكار و تلميحات[ المعنى الحقيقي للـ True و False ] - أمثلة (VB.NETVB6.0)

----------------------------------------------------------------------------------------------------------------------------------------------

• دوال الـ APIs و مايقابلها في الدوت نت ! - (VB.NET)

----------------------------------------------------------------------------------------------------------------------------------------------

#7

مع اني هجرت البيسك من توقف VB4ARAB لكن موضوعك الممتاز شدني .. والخبير خبير .. جربت كثير من برامجك والعابك .. لا اذكر مرة واحدة طلعت رسالة خطأ او هنق الجهاز . ما شاء الله عليك ,,,

هذا اللي عندي ..

تم تعديل هذه المشاركة بواسطة الشـمري في 23 يوليو 2005 في 03:09

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#8

شكرا لك يا استاذ فعلا فوق الرائع الله يجعله في ميزان حسناتك ويوفقك في اعمالك

127gq4.png
#9

جزاك الله خيرا أخي رغيد الطيب

معلومات رائعه

essam.gif

منتديات كوكب الكمبيوتر

لكل جديد في عالم تكنولوجيا المعلومات والكمبيوتر والأخبار العلمية

http://www.planetss.com/vb

#10

السلام عليكم ورحمة الله وبركاته

دائما متميز اخى رغيد واتمنى لك التوفيق والتميز اكثر

اخوك شريف...

مع خالص تحياتى...

;) ;) :rolleyes:

#11

أشكرك أخي علي هذا الكود الجميل

وانا سأجربة الأن

#12

للتميز اصحاب

Linux System Admin

#13

ليست متميز بل رائع و مبدع

#14

هكذا هو رغيد الطيب

بارك الله فيك وجعله الله في ميزان حسناتك

بالتوفيق

مختار أحمد

موقع الويب : http://www.luxorsystems.com

منتدياتنا :http://www.luxorsystems.com/forum/index.php

للمراسلة

luxorsystems@hotmail.com

للاتصال التليفوني

00201228085123

مواضيع مشابهة