لماذا يأخذ كودك وقتا طويلا أثناء التنفيذ


الكاتب الأخ : samerselo


Profiling هو معرفة تصرفات كودك و قسم كبير منه هو معرفة فيما إذا كان هذا الكود يأخذ وقتا طويلا للتنفيذ. كما لايجب القيام به منذ البدء بالتطوير ولكنه يصبح ضروريا عند تدقيق الأنظمة التي تسير ببطء كما أنه يصبح مفيدا قرب الانتهاء من التطوير وخاصة لتلك الأنظمة التي تعمل خارج المجال المقبول

في فيجول ستوديو 2005 وخاصة إصدارة Team لديها أدوات رائعة لـ Profiling ولكنها مصممة للعمل ضمن بيئة التطوير. و الـ Auto Profiler الذي يبقى مع كودك يجعلك تقرر متى تشغله ومتى توقفه. وهذه المقالة تعرض كيفية توظيف بعض الوظائف المفيدة في الدوت نيت لبناء Auto Profiler سهل الاستخدام يمكنه توقيت سطر واحد أو برنامج كامل

Implementing the Timestamp Class

الخطوة الأولى هي بناء فئة تتعقب وتوقف الأوقات. ويجب أن تعلم أنه عندما تبدأ بتوقيت قطعة من الكود والوقت المار منذ البدء يمكنك استخدام الفئة DateTime من أجل توقيت البداية والنهاية متضمنا حسابات الوقت المنتهي لهذه الفئة والكود التالي يبين فئة Stamp

رمز برمجي:
Friend Class Stamp
   Private start As DateTime
   Public Sub New()
      start = DateTime.Now
   End Sub
   Public ReadOnly Property ElapsedTimeString() As String
      Get
         Return ElapsedTime.ToString()
      End Get
   End Property
   Public ReadOnly Property StartTime()
      Get
         Return start.ToLongTimeString()
      End Get
   End Property
   Public ReadOnly Property ElapsedTime() As TimeSpan
      Get
         Return DateTime.Now.Subtract(start)
      End Get
   End Property
End Class

Implementing the MarkTime Class

ولإبقاء الفئة سهلة الاستخدام ضع معظم العمل عليك والفئة التالية MarkTime تستخدم تتبع عام لكائن Stamp وهي تبني كائن Stamp وتضعه في الذاكرة وتعيد علامة الوقت وستحتاج هنا للمكدس Stack لتتبع التكرار فمثلا عندما تكرر الطريقة نفسها عشر مرات فإنك تضيف عشر علامات بدء لمكدس MarkTime قبل أن تحتسب أوقات الانتهاء والكود التالي يبين الفئة MarkTime

رمز برمجي:
Friend Class MarkTime
   Private stack As Stack(Of Stamp) = Nothing
   Public Sub New()
      stack = New Stack(Of Stamp)()
   End Sub
   Public Function AddStart() As String
      Dim start As Stamp = New Stamp()
      stack.Push(start)
      Return start.StartTime
   End Function
   Public Function RemoveStart() As String
      If (stack.Peek() Is Nothing = False) Then
         Return stack.Pop().ElapsedTimeString
      Else
         Return ""
      End If
   End Function
End Class

بناء AutoProfiler باستخدام جدول التهشير Hashtable

وأخيرا الـ AutoProfiler يحتوي على باني مشترك shared constructor هو Sub New و طريقتان مشتركتان هما Stopp و Start الطريقة Start تستدعي الطريقة المشتركة GetKey التي تستخدم StackTrace و الانعكاس Reflection للحصول على الاسم الكامل للطرقة المستدعية وهذا الاسم يصبح المفتاح Key في جدول التهشير Hashtable وهنا المستخدم لن يحتاج لمعرفة أي الطرق يتم قياسها لأن جدول التهشير Hashtable يقوم بذلك وإذا تم استدعاء الطريقة عدة مرات وكان المدخل موجود سابقا في جدول التهشير Hashtable سيتم معاملة التوقفات و الابتداءات الإضافية بنفس كائن MarkTime في جدول التهشير Hashtable وكل ما سيحتاجه مستخدم AutoProfiler هو استدعاء AutoProfiler.Start أو AutoProfiler.Stopp وستقوم الفئة Class بمتابعة وقت البدء والتوقف والمستدعي و الكود التالي يحتوي الفئة MarkTime

رمز برمجي:
Public Class AutoProfiler
   Private Shared hash As Hashtable = Nothing
   Private Shared output As OutputType = OutputType.Console
   Shared Sub New()
      hash = New Hashtable
   End Sub
   Private Shared Function GetKey() As String
      Const mask As String = "{0}.{1}"
      Dim trace As StackTrace = New StackTrace
      Dim method As MethodBase = trace.GetFrame(2).GetMethod()
      Return String.Format(mask, _
         method.ReflectedType.FullName, method.Name)
   End Function
   Public Shared Property OutputTo() As OutputType
      Get
         Return output
      End Get
      Set(ByVal value As OutputType)
         output = value
      End Set
   End Property
   <Conditional("DEBUG")> _
   Public Shared Sub Start()
      Dim marker As MarkTime = Nothing
      Dim key As String = GetKey()
      If (hash(key) Is Nothing) Then
         marker = New MarkTime()
         hash.Add(key, marker)
      Else
         marker = CType(hash(key), MarkTime)
      End If
      WriteLine("Started {0} at {1}", key, marker.AddStart())
   End Sub
   <Conditional("DEBUG")> _
   Public Shared Sub Stopp()
      Dim marker As MarkTime = Nothing
      Dim key As String = GetKey()
      If (hash(key) Is Nothing) Then
         Throw New ArgumentOutOfRangeException(key, _
            "Can't find start time entry")
      End If
      marker = CType(hash(key), MarkTime)
      WriteLine("Stopped: {0}, elapsed time {1}", _
         key, marker.RemoveStart())
   End Sub
   Private Shared Sub WriteLine(ByVal format As String, _
      ByVal ParamArray args() As Object)
      If (output = OutputType.Console) Then
         System.Console.WriteLine(String.Format(format, args))
      Else    ' debug
         System.Diagnostics.Debug.WriteLine( _
            String.Format(format, args))
      End If
   End Sub
End Class

و الكود التالي يحتوي على النص الكامل لـ AutoProfiler متضمنا برنامج Console كمثال يبين سهولة استخدام هذه الطريقة

رمز برمجي:
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Reflection
Imports System.Text

Module Module1
   Sub Main()
      Test()
   End Sub
   Sub Test()
      Profiler.AutoProfiler.Start()
      System.Threading.Thread.Sleep(5000)
      Profiler.AutoProfiler.Stopp()
      Console.ReadLine()
   End Sub
End Module
Namespace Profiler
   Public Enum OutputType
      Console
      Debug
      Window
   End Enum
   Public Class AutoProfiler
      Private Shared hash As Hashtable = Nothing
      Private Shared output As OutputType = OutputType.Console
      Shared Sub New()
         hash = New Hashtable
      End Sub
      Private Shared Function GetKey() As String
         Const mask As String = "{0}.{1}"
         Dim trace As StackTrace = New StackTrace
         Dim method As MethodBase = trace.GetFrame(2).GetMethod()
         Return String.Format(mask, _
            method.ReflectedType.FullName, method.Name)
      End Function
      Public Shared Property OutputTo() As OutputType
         Get
            Return output
         End Get
            Set(ByVal value As OutputType)
            output = value
         End Set
      End Property
      <Conditional("DEBUG")> _
      Public Shared Sub Start()
         Dim marker As MarkTime = Nothing
         Dim key As String = GetKey()
         If (hash(key) Is Nothing) Then
            marker = New MarkTime()
            hash.Add(key, marker)
         Else
            marker = CType(hash(key), MarkTime)
         End If
         WriteLine("Started {0} at {1}", key, marker.AddStart())
      End Sub
      <Conditional("DEBUG")> _
      Public Shared Sub Stopp()
         Dim marker As MarkTime = Nothing
         Dim key As String = GetKey()
         If (hash(key) Is Nothing) Then
            Throw New ArgumentOutOfRangeException(key, _
               "Can't find start time entry")
         End If
         marker = CType(hash(key), MarkTime)
         WriteLine("Stopped: {0}, elapsed time {1}", _
               key, marker.RemoveStart())
      End Sub
      Private Shared Sub WriteLine(ByVal format As String, _
         ByVal ParamArray args() As Object)
         If (output = OutputType.Console) Then
            System.Console.WriteLine(String.Format(format, args))
         Else ' debug
            System.Diagnostics.Debug.WriteLine( _
               String.Format(format, args))
         End If
      End Sub
   End Class
   Friend Class MarkTime
      Private stack As Stack(Of Stamp) = Nothing
      Public Sub New()
         stack = New Stack(Of Stamp)()
      End Sub
      Public Function AddStart() As String
         Dim start As Stamp = New Stamp()
         stack.Push(start)
         Return start.StartTime
      End Function
      Public Function RemoveStart() As String
         If (stack.Peek() Is Nothing = False) Then
            Return stack.Pop().ElapsedTimeString
         Else
            Return ""
         End If
      End Function
   End Class
   Friend Class Stamp
      Private start As DateTime
      Public Sub New()
         start = DateTime.Now
      End Sub
      Public ReadOnly Property ElapsedTimeString() As String
         Get
            Return ElapsedTime.ToString()
         End Get
      End Property
      Public ReadOnly Property StartTime()
         Get
            Return start.ToLongTimeString()
         End Get
      End Property
      Public ReadOnly Property ElapsedTime() As TimeSpan
         Get
            Return DateTime.Now.Subtract(start)
         End Get
      End Property
   End Class
End Namespace

توقيت كودك

لقد قمت للتو بإنشاء AutoProfiler يمكن المستخدم من توقيت أي أمر أو عدة أوامر أو حتى قطعات كبيرة من الكود فقط باستدعاء AutoProfiler.Start و AutoProfiler.Stopp حيث تقوم هذه التقنية بتوظيف generics و hashtables و reflection ومعرفة الفئة StackTrace حيث ستجدها مفيدة عندما تواجه كودا يتم تنفيذه بأبطأ من المقبول

Advertisements
  1. لا توجد تعليقات حتى الأن.
  1. No trackbacks yet.

شاركنا برأيك ,لكي نرقى بالمدونة,يمكنك أضافة تعليق عن طريق حسابك في Facebook

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s

%d مدونون معجبون بهذه: