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

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

مغلق
بدأه محمد سامر أبو سلو في 24 فبراير 2007 · 4 رد · 891 مشاهدة · في Microsoft Visual Basic.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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 حيث ستجدها مفيدة عندما تواجه كودا يتم تنفيذه بأبطأ من المقبول

موضوع منشور سابقا في مجلة الفريق العربي للبرمجة

مترجم للفائدة

عن عائشة رضي الله عنها أن النبي صلى الله عليه وسلم قال: إن الله يحب إذا عمل أحدكم عملا أن يتقنه

نعيب زماننا والعيب فينا ... وما لزماننا عيب سوانا

ونهجو ذا الزمان بغير ذنب ... ولو نطق الزمان لنا هجانا

محمد سامر أبو سلو

#2

موضوع مهم جداا ورائع ، جزاك الله كل خير

#3

موضوع مفيد وجميل، ويمكن الاستفادة منه

بارك الله بك وجزاك عنا خيرا على مواضيعك التعليمية الهامة

اللهم لا سهل الا ماجعلته سهلا، وانت تجعل الصعب ان شئت سهلا

83_45a7168be2ddb.jpg

#4

ممتاز جداُ

الموضوع بالفعل رائع ويحتاج مننا جميعا ان نبني برامجنا بأسلوب صحيح وليس عشوائي لتفادي مشاكل البطئ واخطاء وقت التنفيذ ..

شكرا لك اخي .

#5

يعطيك العافية أخ محمد

كم هو جميل أن نرى من منحهم الله علما أن يشاركوا خبراتهم مع من هم في مستواهم أو أقل منهم خبرة لتعم الفائدة للجميع

لك احترامي على هذه المشاركة القيمة

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

تم تعديل هذه المشاركة بواسطة a7sanwa7ed في 28 فبراير 2007 في 00:30

336.jpg

هذا الموضوع مغلق.

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…