مثال تجمع دلفي الموضوع باستخدام AsyncCalls

هذا هو مشروعي التجريبي التالي لمعرفة مكتبة الترابط الخاصة بـ Delphi التي تناسبني بشكل أفضل مع مهمة "فحص الملفات" التي أرغب في معالجتها في سلاسل رسائل متعددة / في مجموعة مؤشرات ترابط.

لتكرار هدفي: تحويل "مسح الملفات" التسلسلي الخاص بي لملفات 500-2000 + من النهج غير المترابط إلى ملف مترابط. لا يجب أن يكون لدي 500 مؤشر ترابط قيد التشغيل في وقت واحد ، وبالتالي أود استخدام تجمع مؤشر ترابط. تجمع مؤشر الترابط عبارة عن فئة تشبه قائمة الانتظار تقوم بتغذية عدد من سلاسل العمليات قيد التشغيل بالمهمة التالية من قائمة الانتظار.

تم إجراء المحاولة الأولى (الأساسية جدًا) ببساطة عن طريق توسيع فئة TThread وتنفيذ أسلوب التنفيذ (محلل السلسلة المترابطة).

نظرًا لأن دلفي لا تحتوي على فئة تجمع سلاسل رسائل تم تنفيذها خارج الصندوق ، في محاولتي الثانية حاولت استخدام OmniThreadLibrary من Primoz Gabrijelcic.

إن OTL رائع ، ولديه عدد كبير من الطرق لتشغيل مهمة في الخلفية ، وهي طريقة للذهاب إذا كنت تريد أن يكون لديك أسلوب "إطلاق النار والنسيان" لتسليم التنفيذ المترابطة لقطع من التعليمات البرمجية الخاصة بك.

AsyncCalls بواسطة أندرياس هاوسلادين

instagram viewer
ملاحظة: سيكون من السهل متابعة ما يلي إذا قمت أولاً بتنزيل شفرة المصدر.

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

من مدونة Andy: باستخدام AsyncCalls ، يمكنك تنفيذ وظائف متعددة في نفس الوقت ومزامنتها في كل نقطة في الوظيفة أو الطريقة التي بدأتها... تقدم وحدة AsyncCalls مجموعة متنوعة من النماذج الأولية للوظائف لاستدعاء الوظائف غير المتزامنة... ينفذ تجمع الخيط! التثبيت سهل للغاية: ما عليك سوى استخدام عمليات غير متزامنة من أي من وحداتك وسيكون لديك وصول فوري إلى أشياء مثل "التنفيذ في سلسلة محادثات منفصلة ، ومزامنة واجهة المستخدم الرئيسية ، والانتظار حتى الانتهاء".

بجانب الاستخدام المجاني (ترخيص MPL) AsyncCalls ، ينشر آندي بشكل متكرر إصلاحاته الخاصة لـ Delphi IDE مثل "دلفي تسريع"و"DDevExtensions"أنا متأكد من أنك سمعت (إذا لم تكن تستخدم بالفعل).

AsyncCalls في العمل

بشكل أساسي ، تقوم جميع وظائف AsyncCall بإرجاع واجهة IAsyncCall التي تسمح بمزامنة الوظائف. يكشف IAsnycCall الطرق التالية:

 //الإصدار 2.98 من asynccalls.pas
IAsyncCall = الواجهة
// ينتظر حتى انتهاء الوظيفة وإرجاع القيمة المرجعة
مزامنة الوظيفة: عدد صحيح ؛
// ترجع True عند الانتهاء من وظيفة غير متزامنة
وظيفة منتهية: منطقية ؛
// تقوم بإرجاع قيمة الإرجاع للدالة غير المتزامنة ، عندما يكون Finished هو TRUE
دالة ReturnValue: عدد صحيح؛
// يخبر AsyncCalls أنه لا يجب تنفيذ الوظيفة المعينة في threa الحالي
إجراء ForceDifferentThread ؛
النهاية؛

فيما يلي مثال لاستدعاء طريقة تتوقع معلمتين صحيحتين (إرجاع IAsyncCall):

 TASyncCalls. استدعاء (AsyncMethod، i، Random (500)) ؛
وظيفة TAsyncCallsForm. AsyncMethod (taskNr ، sleepTime: عدد صحيح): عدد صحيح ؛
ابدأ
النتيجة: = sleepTime ؛
النوم (وقت النوم) ؛
TASyncCalls. VCLInvoke (
إجراء
ابدأ
السجل (التنسيق ('تم> nr:٪ d / المهام:٪ d / slept:٪ d'، [tasknr، asyncHelper. TaskCount ، sleepTime])) ؛
النهاية);
النهاية;

TAsyncCalls. VCLInvoke هي طريقة للقيام بالمزامنة مع خيطك الرئيسي (الخيط الرئيسي للتطبيق - واجهة مستخدم التطبيق الخاص بك). VCLInvoke يعود على الفور. سيتم تنفيذ الطريقة المجهولة في الخيط الرئيسي. هناك أيضًا VCLSync الذي يرجع عندما تم استدعاء الأسلوب المجهول في مؤشر الترابط الرئيسي.

تجمع الموضوع في AsyncCalls

العودة إلى مهمتي "فحص الملفات": عند التغذية (في حلقة for) تجمع مؤشر الترابط غير المتزامن مع سلسلة من TAsyncCalls. استدعاء مكالمات () ، ستتم إضافة المهام إلى التجمع الداخلي وسيتم تنفيذها "عندما يحين الوقت" (عندما تنتهي المكالمات المضافة سابقًا).

انتظر جميع IAsyncCalls للانتهاء

تنتظر الدالة AsyncMultiSync المحددة في asnyccalls انتهاء مكالمات async (والمقابض الأخرى). هناك عدد قليل مثقلة طرق للاتصال بـ AsyncMultiSync ، وهنا أبسط طريقة:

وظيفة AsyncMultiSync (مقدار ثابت قائمة: مصفوفة من IAsyncCall ؛ WaitAll: منطقي = صحيح ؛ ميلي ثانية: الكاردينال = INFINITE): الكاردينال ؛ 

إذا كنت أرغب في تنفيذ "انتظر الكل" ، فأنا بحاجة إلى ملء مجموعة من IAsyncCall والقيام بـ AsyncMultiSync في شرائح من 61.

مساعد AsnycCalls

إليك قطعة من TAsyncCallsHelper:

تحذير: كود جزئي! (الرمز الكامل متاح للتنزيل)
الاستخدامات غير متزامن
اكتب
TIAsyncCallArray = مصفوفة من IAsyncCall ؛
TIAsyncCallArrays = مصفوفة من TIAsyncCallArray ؛
TAsyncCallsHelper = صف دراسي
نشر
fTasks: TIAsyncCallArrays؛
خاصية المهام: TIAsyncCallArrays اقرأ المهام ؛
عامة
إجراء إضافة مهمة(مقدار ثابت استدعاء: IAsyncCall) ؛
إجراء WaitAll ؛
النهاية;
تحذير: كود جزئي!
إجراء TAsyncCallsHelper. WaitAll ؛
فار
i: عدد صحيح ؛
ابدأ
إلى عن على i: = High (المهام) نازل إلى منخفض (المهام) فعل
ابدأ
غير متزامن. AsyncMultiSync (المهام [i]) ؛
النهاية;
النهاية;

بهذه الطريقة يمكنني "انتظار الكل" في أجزاء من 61 (MAXIMUM_ASYNC_WAIT_OBJECTS) - أي انتظار صفائف IAsyncCall.

مع ما سبق ، يبدو الكود الرئيسي لتغذية تجمع الموضوع:

إجراء TAsyncCallsForm.btnAddTasksClick (المرسل: TObject) ؛
مقدار ثابت
nrItems = 200 ؛
فار
i: عدد صحيح ؛
ابدأ
مساعد غير متزامن. MaxThreads: = 2 * النظام. CPUCount ؛
ClearLog ("البداية") ؛
إلى عن على i: = 1 إلى nrItems فعل
ابدأ
مساعد غير متزامن. إضافة مهمة (TAsyncCalls. استدعاء (AsyncMethod، i، Random (500))) ؛
النهاية;
تسجيل الدخول ('all in') ؛
// انتظر الكل
//asyncHelper.WaitAll;
// أو السماح بإلغاء الكل لم يبدأ بالنقر فوق الزر "إلغاء الكل":

بينما لا مساعد غير متزامن. الكل فعل تطبيق. الرسائل العملية ؛
السجل ("انتهى") ؛
النهاية;

ألغ الكل؟ - يجب تغيير AsyncCalls.pas :(

أود أيضًا أن أحصل على طريقة "لإلغاء" تلك المهام الموجودة في التجمع ولكنها تنتظر تنفيذها.

لسوء الحظ ، لا يوفر AsyncCalls.pas طريقة بسيطة لإلغاء مهمة بمجرد إضافتها إلى تجمع سلسلة المحادثات. لا يوجد IAsyncCall. قم بإلغاء أو IAsyncCall. DontDoIfNotAlreadyExecuting أو IAsyncCall. NeverMindMe.

من أجل هذا العمل كان علي تغيير AsyncCalls.pas بمحاولة تغييره بأقل قدر ممكن - لذلك أنه عندما يصدر Andy إصدارًا جديدًا ، لا يلزمني سوى إضافة بضعة أسطر للحصول على فكرتي "إلغاء المهمة" يعمل.

إليك ما فعلته: لقد أضفت "إلغاء الإجراء" إلى IAsyncCall. يعين إجراء الإلغاء حقل "FCancelled" (مضاف) الذي يتم فحصه عندما يكون التجمع على وشك بدء تنفيذ المهمة. كنت بحاجة إلى تغيير IAsyncCall قليلاً. انتهى (بحيث تنتهي تقارير المكالمة حتى عند إلغائها) و TAsyncCall. إجراء InternExecuteAsyncCall (وليس لتنفيذ المكالمة إذا تم إلغاؤها).

يمكنك استخدام نظام WinMerge لتحديد الاختلافات بسهولة بين ملف asynccall.pas الأصلي من Andy وإصداري المعدل (مضمن في التنزيل).

يمكنك تنزيل شفرة المصدر الكاملة واستكشافها.

اعتراف

تنويه! :)

ال إلغاءاستدعاء الأسلوب يوقف استدعاء AsyncCall. إذا تمت معالجة AsyncCall بالفعل ، فلن يكون لاستدعاء CancelInvocation أي تأثير وستُرجع وظيفة Canceled False خطأ لأن AsyncCall لم يتم إلغاؤه.
ال ألغيت ترجع الطريقة True إذا تم إلغاء AsyncCall بواسطة CancelInvocation.
ال ننسى طريقة إلغاء ربط واجهة IAsyncCall من AsyncCall الداخلية. هذا يعني أنه إذا اختفى المرجع الأخير إلى واجهة IAsyncCall ، فسيستمر تنفيذ المكالمة غير المتزامنة. سوف تطرح أساليب الواجهة استثناءً إذا تم استدعاؤها بعد استدعاء Forget. يجب ألا تستدعي وظيفة المتزامن في سلسلة المحادثات الرئيسية لأنه يمكن تنفيذها بعد TThread. أغلقت RTL آلية التزامن / قائمة الانتظار مما قد يتسبب في قفل تام.

ومع ذلك ، لاحظ أنه لا يزال بإمكانك الاستفادة من AsyncCallsHelper إذا كنت بحاجة إلى الانتظار حتى تنتهي جميع مكالمات async باستخدام "asyncHelper". WaitAll "؛ أو إذا كنت بحاجة إلى "CancelAll".

instagram story viewer