منذ 4 ساعة مضت
(آخر تعديل لهذه المشاركة: منذ 3 ساعة مضت بواسطة الفجر الابيض.)
السلام عليكم ورحمة الله
من الامور التي ازعجتني كثيرا في دلفي هي عندما احتجت لان ادخل في استخدام برمجة متوازية للعمليات التي كنت بحاجة الى ادارتها والبيانات التي كنت ارسلها واستقبلها
في .net الادارة سهلة وكل شئ يتم بدون تدخل المستخدم ولكن في دلفي يجب ان تكون حذرا جدا في هذا وتدير كل شئ من بدايته الى نهايته يدويا وبحرص شديد
لندخل في الموضوع
تعتبر الـ Tasks في دلفي جزءا اساسيا من مكتبة البرمجة المتوازية (Parallel Programming Library - PPL) التي تم تقديمها لتسهيل التعامل مع تعدد المهام (Multi-threading). الهدف منها هو تنفيذ عمليات برمجية في الخلفية دون ان يتوقف البرنامج عن الاستجابة.
فيما يلي شرح مبسط وشامل حول كيفية استخدامها:
1. ما هي الـ Task؟
ببساطة، الـ Task هي وحدة عمل يتم ارسالها لتعمل بشكل منفصل عن الخيط الرئيسي (Main Thread). بدلا من انشاء TThread يدويا وادارة دورة حياته، تقوم الـ Task بادارة ذلك تلقائيا باستخدام "مجمع الخيوط" (Thread Pool)، مما يوفر استهلاكا اقل لموارد الجهاز.
2. كيفية الاستخدام الاساسية
لاستخدام الـ Tasks، يجب عليك اضافة الوحدة System.Threading الى قائمة الـ uses.
مثال عملي:
3. مميزات استخدام الـ Tasks
سهولة الكود: لا تحتاج لتعريف كلاس جديد لكل خيط.
الادارة الذكية: يقوم النظام بتحديد عدد الخيوط بناء على قدرة المعالج.
عدم تجميد الشاشة: يبقى المستخدم قادرا على الضغط على الازرار وتحريك النافذة اثناء العمل.
4. نصائح هامة جدا
تحديث الواجهة: ابدا لا تقم بتغيير خصائص المكونات (مثل Label.Caption) مباشرة من داخل الـ Task. استخدم دائما TThread.Synchronize او TThread.Queue.
المتغيرات المحلية: كن حذرا عند استخدام المتغيرات التي قد تختفي من الذاكرة قبل انتهاء المهمة.
معالجة الاخطاء: يفضل استخدام try..except داخل الـ Task لان الاخطاء بداخلها قد لا تظهر بشكل مباشر للمستخدم.
5. انتظار مجموعة من المهام (WaitAll)
يمكنك تشغيل عدة مهام والانتظار حتى تنتهي جميعا قبل الانتقال للخطوة التالية:
كما هو مذكور اي شئ يمس الواجهة ابدا ومطلقا ولا تحاول ان تلمسه وانت خارج من TThread.Queue(nil, procedure
نفذ المهمة التي تحتاج الى وقت طويل بداخل
وعندما تنتهي منها ارجع الى الواجهة وافعل ماتريد هنا
وكما تلاحظون لم اقم بقتل الكائن Free وهذا لان في دلفي، عند التعامل مع الـ Tasks، نحن لا نستخدم Free يدوياً لأن الـ ITask هو عبارة عن Interface.
إليك توضيح لهذه النقطة بدون علامات تشكيل:
إدارة الذاكرة التلقائية: بما أن الـ Task يتم التعامل معه كـ Interface، فإن دلفي تستخدم نظام (Reference Counting). هذا يعني أن الكائن يتم تدميره وتحرير ذاكرته تلقائياً بمجرد انتهاء العمل منه وعدم وجود أي متغير يشير إليه.
دورة حياة المهمة: بمجرد انتهاء الإجراء (Procedure) الموجود داخل المهمة، وبمجرد أن يفقد المتغير aTask نطاقه (Scope)، يقوم النظام بتنظيف كل شيء خلفه.
تجنب الأخطاء: محاولة تحرير (Free) المهمة يدوياً قد تؤدي إلى أخطاء في الذاكرة (Access Violation)، لأن "مجمع الخيوط" (Thread Pool) هو المسؤول عن إدارة عمر هذه الخيوط وإعادتها للمجموعة أو تدميرها.
نصيحة إضافية: إذا كنت تستخدم كائنات أخرى (مثل TStringList أو TQuery) داخل المهمة، فهذه الكائنات يجب تحريرها يدوياً باستخدام try..finally و Free داخل كود المهمة نفسه، لأنها كائنات عادية وليست Interfaces.
مثال سريع للتوضيح:
هذا شئ لا غنى عنه للتعامل مع قواعد البيانات على الانترنت او تحميل ورفع الملفات وبدون هذا الاسلوب فسوف تواجه مشاكل لا حد لها
ودمتم بخير
من الامور التي ازعجتني كثيرا في دلفي هي عندما احتجت لان ادخل في استخدام برمجة متوازية للعمليات التي كنت بحاجة الى ادارتها والبيانات التي كنت ارسلها واستقبلها
في .net الادارة سهلة وكل شئ يتم بدون تدخل المستخدم ولكن في دلفي يجب ان تكون حذرا جدا في هذا وتدير كل شئ من بدايته الى نهايته يدويا وبحرص شديد
لندخل في الموضوع
تعتبر الـ Tasks في دلفي جزءا اساسيا من مكتبة البرمجة المتوازية (Parallel Programming Library - PPL) التي تم تقديمها لتسهيل التعامل مع تعدد المهام (Multi-threading). الهدف منها هو تنفيذ عمليات برمجية في الخلفية دون ان يتوقف البرنامج عن الاستجابة.
فيما يلي شرح مبسط وشامل حول كيفية استخدامها:
1. ما هي الـ Task؟
ببساطة، الـ Task هي وحدة عمل يتم ارسالها لتعمل بشكل منفصل عن الخيط الرئيسي (Main Thread). بدلا من انشاء TThread يدويا وادارة دورة حياته، تقوم الـ Task بادارة ذلك تلقائيا باستخدام "مجمع الخيوط" (Thread Pool)، مما يوفر استهلاكا اقل لموارد الجهاز.
2. كيفية الاستخدام الاساسية
لاستخدام الـ Tasks، يجب عليك اضافة الوحدة System.Threading الى قائمة الـ uses.
مثال عملي:
كود :
uses System.Threading;
procedure TForm1.Button1Click(Sender: TObject);
var
aTask: ITask;
begin
// انشاء وبدء المهمة
aTask := TTask.Create(procedure
begin
// كود يستغرق وقتا طويلا هنا
Sleep(3000);
// العودة لتحديث الواجهة البرمجية بامان
TThread.Queue(nil, procedure
begin
ShowMessage('تم الانتهاء من المهمة بنجاح!');
end);
end);
aTask.Start;
end;3. مميزات استخدام الـ Tasks
سهولة الكود: لا تحتاج لتعريف كلاس جديد لكل خيط.
الادارة الذكية: يقوم النظام بتحديد عدد الخيوط بناء على قدرة المعالج.
عدم تجميد الشاشة: يبقى المستخدم قادرا على الضغط على الازرار وتحريك النافذة اثناء العمل.
4. نصائح هامة جدا
تحديث الواجهة: ابدا لا تقم بتغيير خصائص المكونات (مثل Label.Caption) مباشرة من داخل الـ Task. استخدم دائما TThread.Synchronize او TThread.Queue.
المتغيرات المحلية: كن حذرا عند استخدام المتغيرات التي قد تختفي من الذاكرة قبل انتهاء المهمة.
معالجة الاخطاء: يفضل استخدام try..except داخل الـ Task لان الاخطاء بداخلها قد لا تظهر بشكل مباشر للمستخدم.
5. انتظار مجموعة من المهام (WaitAll)
يمكنك تشغيل عدة مهام والانتظار حتى تنتهي جميعا قبل الانتقال للخطوة التالية:
كود :
var
tasks: array of ITask;
begin
SetLength(tasks, 2);
tasks[0] := TTask.Create(procedure begin Sleep(1000); end);
tasks[0].Start;
tasks[1] := TTask.Create(procedure begin Sleep(2000); end);
tasks[1].Start;
// الانتظار حتى تنتهي المهمتان
TTask.WaitForAll(tasks);
ShowMessage('كل المهام اكتملت');
end;كما هو مذكور اي شئ يمس الواجهة ابدا ومطلقا ولا تحاول ان تلمسه وانت خارج من TThread.Queue(nil, procedure
نفذ المهمة التي تحتاج الى وقت طويل بداخل
كود :
aTask := TTask.Create(procedure
beginوعندما تنتهي منها ارجع الى الواجهة وافعل ماتريد هنا
كود :
TThread.Queue(nil, procedure
begin
ShowMessage('تم الانتهاء من المهمة بنجاح!');
end);وكما تلاحظون لم اقم بقتل الكائن Free وهذا لان في دلفي، عند التعامل مع الـ Tasks، نحن لا نستخدم Free يدوياً لأن الـ ITask هو عبارة عن Interface.
إليك توضيح لهذه النقطة بدون علامات تشكيل:
إدارة الذاكرة التلقائية: بما أن الـ Task يتم التعامل معه كـ Interface، فإن دلفي تستخدم نظام (Reference Counting). هذا يعني أن الكائن يتم تدميره وتحرير ذاكرته تلقائياً بمجرد انتهاء العمل منه وعدم وجود أي متغير يشير إليه.
دورة حياة المهمة: بمجرد انتهاء الإجراء (Procedure) الموجود داخل المهمة، وبمجرد أن يفقد المتغير aTask نطاقه (Scope)، يقوم النظام بتنظيف كل شيء خلفه.
تجنب الأخطاء: محاولة تحرير (Free) المهمة يدوياً قد تؤدي إلى أخطاء في الذاكرة (Access Violation)، لأن "مجمع الخيوط" (Thread Pool) هو المسؤول عن إدارة عمر هذه الخيوط وإعادتها للمجموعة أو تدميرها.
نصيحة إضافية: إذا كنت تستخدم كائنات أخرى (مثل TStringList أو TQuery) داخل المهمة، فهذه الكائنات يجب تحريرها يدوياً باستخدام try..finally و Free داخل كود المهمة نفسه، لأنها كائنات عادية وليست Interfaces.
مثال سريع للتوضيح:
كود :
TTask.Run(procedure
var
List: TStringList;
begin
List := TStringList.Create;
try
// افعل شيئا بالقائمة
finally
List.Free; // هنا يجب التحرير يدويا للكائنات الداخلية فقط
end;
end);هذا شئ لا غنى عنه للتعامل مع قواعد البيانات على الانترنت او تحميل ورفع الملفات وبدون هذا الاسلوب فسوف تواجه مشاكل لا حد لها
ودمتم بخير
إذا رأيت منتجاً مجانياً فأعلم بأنك أنت السّلعة


![[-]](https://delphi4arab.net/forum/D4A2020/collapse.png)