تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
لماذا يأخذ كودك وقتا طويلا أثناء التنفيذ
#1
كاتب الموضوع : 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 حيث ستجدها مفيدة عندما تواجه كودا يتم تنفيذه بأبطأ من المقبول
}}}
تم الشكر بواسطة:



التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم