غالباً ما تصبح وحدات الماكرو في LibreOffice Calc بطيئة في جداول البيانات الكبيرة لسبب بسيط: يقضي الماكرو وقتاً أطول في عبور حدود كائن UNO مقارنةً بإجراء العملية الحسابية الفعلية. فقراءة خلية واحدة وتغييرها وكتابتها مرة أخرى آلاف المرات قد يكون أكثر تكلفة بكثير من نقل البيانات نفسها في كتل أكبر.
لا يكمن الهدف في جعل كل ماكرو "سريعًا" بشكل مطلق. بل يجب أن يُنتج التحسين الفعال نفس المخرجات، ويُنجز في وقت أقل على نفس مجموعة البيانات، ويحافظ على استجابة برنامج Calc بما يكفي لسير العمل، ويتجنب إحداث مشاكل جديدة في الدقة أو الذاكرة. وتركز التقنيات المذكورة أدناه على هذه النتائج القابلة للقياس.
اعتبارًا من أكتوبر 2026، تُحدد وثائق LibreOffice SDK الحالية واجهات جداول البيانات المستخدمة هنا في مرجع واجهة برمجة التطبيقات (API) الخاص بـ LibreOffice 26.8. وتُعدّ الطرق الأساسية واجهات UNO راسخة وليست ميزة أداء مُستحدثة.
1. قم بقياس الماكرو قبل تغييره
ابدأ بخط أساس قابل للتكرار. يوفر LibreOffice Basic ميزة GetSystemTicks()قياس دورات النظام وتحسين العمليات، والتي يصفها دليل المساعدة الرسمي بأنها طريقة لقياس دورات النظام وتحسين العمليات. قم بتغليف جزء الماكرو الذي ترغب بتحسينه فعليًا بدلاً من قياس توقيت فتح المصنف، أو مطالبات المستخدم، أو الإعدادات غير ذات الصلة.
Dim t0 As Long, elapsed As Long
t0 = GetSystemTicks()
' Run the work you want to measure here.
elapsed = GetSystemTicks() - t0
MsgBox "Elapsed ticks: " & elapsed
نفّذ العملية نفسها عدة مرات على النسخة نفسها من الملف. قد تختلف النتيجة في المرة الأولى بسبب ذاكرة التخزين المؤقت لنظام الملفات، أو حالة الصيغة، أو أي عملية أخرى تُنفّذ لمرة واحدة. سجّل حجم مجموعة البيانات، والنطاق المُعالَج، وما إذا كان الحساب التلقائي مُفعّلاً، لضمان دقة المقارنات.
لا تقتصر النتيجة الجيدة على مجرد انخفاض رقم التوقيت. تأكد من أن عدد الصفوف، والمجاميع، والصيغ، وقيم النصوص، والتواريخ، وأي نطاقات إخراج لا تزال مطابقة للخط الأساسي.
المرجع الرسمي: مساعدة LibreOffice: دالة GetSystemTicks .
2. قم بإزالة عمليات القراءة والكتابة خلية تلو الأخرى أولاً
إذا قام ماكرو بالتكرار عبر نطاق واسع واستدعى دوالًا مثل `foo` بشكل متكرر getCellByPosition()، فعادةً ما يكون هذا النمط هو أول ما يجب البحث عنه. توفر واجهة برمجة تطبيقات UNO XCellRangeData.getDataArray()دوالًا setDataArray()خاصة لنقل نطاق خلايا كامل كمصفوفة.
تنص واجهة برمجة التطبيقات الرسمية على أنها getDataArray()تُرجع سلسلة من الصفوف، يحتوي كل صف منها على أعمدة. تُرجع القيم كسلاسل نصية أو أعداد عشرية. setDataArray()تكتب مصفوفة في نطاق، ويجب أن تتطابق أبعاد المصفوفة مع أبعاد ذلك النطاق.
على سبيل المثال، لنفترض أن الأعمدة من A إلى E تحتوي على المدخلات التي يقوم الماكرو بتحويلها. بدلاً من قراءة كل خلية على حدة، حدد النطاق المحدد مرة واحدة:
Dim doc As Object
Dim sheet As Object
Dim sourceRange As Object
Dim data As Variant
doc = ThisComponent
sheet = doc.Sheets.getByName("Data")
' Example only: A2:E50001.
sourceRange = sheet.getCellRangeByPosition(0, 1, 4, 50000)
data = sourceRange.getDataArray()
تُعالج البيانات dataفي الذاكرة الأساسية، ثم تُكتب مصفوفة النتائج إلى نطاق الوجهة المطابق في عملية واحدة. هذا يقلل عدد استدعاءات UNO بشكل كبير مقارنةً بآلاف عمليات القراءة والكتابة الفردية.
المراجع الرسمية: LibreOffice SDK: XCellRangeData و LibreOffice SDK: XCellRange .
3. قم بمعالجة النطاق الذي تحتاجه فعلياً فقط
يُعد الوصول إلى المصفوفات بكميات كبيرة مفيدًا، لكن تحويل ورقة بيانات ضخمة بلا داعٍ إلى مصفوفة قد ينقل ببساطة عنق الزجاجة إلى الذاكرة. تجنب تضمين أعمدة كاملة أو شبكة Calc بأكملها في التعليمات البرمجية عندما لا تتعامل المهمة إلا مع جدول مُحدد.
حدد آخر صف ذي معنى باستخدام المعلومات المتوفرة في مصنفك: عدد صفوف الاستيراد، أو حجم نتيجة قاعدة البيانات، أو عمود مفتاح محدد، أو نطاق يُنشئه التطبيق. ثم اطلب فقط الصفوف والأعمدة المطلوبة بواسطة الماكرو.
يُعدّ هذا الأمر بالغ الأهمية، خاصةً عندما تحتوي ورقة العمل على تنسيق أقل بكثير من حجم البيانات الفعلية، أو عندما يؤدي المحتوى القديم إلى زيادة المساحة المستخدمة ظاهريًا. تستهلك المصفوفات الكبيرة في الذاكرة ذاكرة الوصول العشوائي (RAM)، وقد يكون تخصيص حجم كبير جدًا أسوأ من معالجة كتل متوسطة الحجم.
متى يجب التحول إلى التجزئة؟
إذا تسبب استخدام مصفوفة واحدة في ارتفاع حاد في استهلاك الذاكرة، أو في فترات توقف طويلة قبل بدء المعالجة، أو اقتربت من حدود الجهاز العملية، فقم بمعالجة البيانات على شكل كتل. على سبيل المثال، عالج عدة آلاف من الصفوف، واكتب النتائج، ثم انتقل إلى الكتلة التالية. لا يوجد حجم كتلة مثالي عالمي؛ اختبر ذلك باستخدام المصنف الفعلي والجهاز.
4. إيقاف إشعارات تحديث الشاشة أثناء العمل المكثف
XModelتُطبّق وثيقة Calc واجهة LibreOffice . lockControllers()وتُعلّق دالتها بعض إشعارات وحدة التحكم المستخدمة لتحديثات العرض، ثم unlockControllers()تستأنفها. وهذا يُقلّل من العمل المرئي غير الضروري أثناء قيام الماكرو بإجراء العديد من التغييرات.
Dim doc As Object
doc = ThisComponent
doc.lockControllers()
' Perform bulk changes here.
doc.unlockControllers()
تنص واجهة برمجة التطبيقات الرسمية صراحةً على ضرورة اقتران عمليات قفل وفتح وحدة التحكم. وهذا يعني أن وحدات الماكرو المستخدمة في الإنتاج يجب أن تتضمن معالجة للأخطاء تضمن unlockControllers()الوصول إلى النتيجة المطلوبة حتى في حالة فشل المعالجة. إن ترك المستند مقفلاً ليس تحسينًا للأداء، بل هو مسار تنظيف معطل.
المرجع الرسمي: LibreOffice SDK: XModel .
5. التحكم في إعادة الحساب التلقائي عندما تهيمن الصيغ على وقت التشغيل
إذا قام الماكرو بتغيير الخلايا التي تُغذي العديد من الصيغ بشكل متكرر، فقد يستغرق برنامج Calc وقتًا طويلاً لإعادة الحساب بينما لا يزال الماكرو يُحدّث القيم الوسيطة. يُتيح مستند جدول البيانات الوصول إلى الواجهة XCalculatable، بما في ذلك isAutomaticCalculationEnabled()و enableAutomaticCalculation()و calculate()و calculateAll().
يتمثل النمط الأكثر أمانًا في تذكر وضع الحساب الحالي للمستخدم، وتعطيل الحساب التلقائي فقط أثناء التحديث، واستعادة الحالة الأصلية بعد ذلك:
Dim doc As Object
Dim wasAutoCalc As Boolean
doc = ThisComponent
wasAutoCalc = doc.isAutomaticCalculationEnabled()
doc.enableAutomaticCalculation(False)
' Perform bulk updates.
doc.enableAutomaticCalculation(wasAutoCalc)
If wasAutoCalc Then
doc.calculate()
End If
calculate()يُعيد حساب الخلايا غير المُعدّلة. calculateAll()يُعيد حساب كل خلية، وهو ما قد يكون مُكلفًا، لذا لا تستدعِه تلقائيًا لمجرد انتهاء ماكرو. استخدم إعادة الحساب الكاملة فقط عندما تتطلب منطق المصنف ذلك فعليًا.
كما هو الحال مع قفل وحدة التحكم، يجب استعادة حالة الحساب في مسار تنظيف الأخطاء. لا ينبغي للماكرو أن يترك مصنف المستخدم في وضع الحساب اليدوي دون تنبيه.
المرجع الرسمي: LibreOffice SDK: XCalculatable .
6. دمج التحسينات بأمان
عادةً ما يكون الهيكل الأكثر فعالية هو: تحديد نطاق دقيق، وقراءته مرة واحدة، ومعالجة القيم في الذاكرة، وكتابة النتائج بشكل مجمع، وقمع واجهة المستخدم غير الضرورية أو إعادة الحساب فقط طوال مدة تلك العملية.
يبدو نمط التنظيف العملي في LibreOffice Basic على النحو التالي:
Sub ProcessLargeData
Dim doc As Object
Dim sheet As Object
Dim dataRange As Object
Dim data As Variant
Dim wasAutoCalc As Boolean
On Error GoTo CleanUp
doc = ThisComponent
sheet = doc.Sheets.getByName("Data")
dataRange = sheet.getCellRangeByPosition(0, 1, 4, 50000)
wasAutoCalc = doc.isAutomaticCalculationEnabled()
doc.lockControllers()
doc.enableAutomaticCalculation(False)
data = dataRange.getDataArray()
' Transform data in memory here.
' Build an output array with dimensions matching its target range.
CleanUp:
doc.enableAutomaticCalculation(wasAutoCalc)
If doc.hasControllersLocked() Then
doc.unlockControllers()
End If
If wasAutoCalc Then
doc.calculate()
End If
End Sub
يُترك منطق التحويل غير مُحدد في المثال عمدًا لأن هذا الجزء يعتمد على مصنفك. يكمن التحسين المهم في شكل سير العمل، وليس في حسابات تجارية مُختلقة.
7. ضع في اعتبارك وظائف Calc المدمجة قبل إعادة تنفيذها
يمكن لبرنامج LibreOffice Basic استدعاء وظائف Calc من خلال com.sun.star.sheet.FunctionAccessالخدمة. إذا كان الماكرو الخاص بك يُنفذ يدويًا عملية بحث أو تجميع أو أي عملية أخرى يوفرها Calc بالفعل، فإن استخدام الوظيفة المدمجة قد يُبسط الكود ويُقلل من الحاجة إلى حلقات تكرار مخصصة.
لا يضمن ذلك أن تتفوق كل دالة مدمجة على كل خوارزمية مخصصة. قارن الأداء مع عبء العمل الفعلي. توضح المساعدة الرسمية كيفية استدعاء دوال Calc من لغة Basic، وتشير إلى أن أسماء الدوال مُقدمة باللغة الإنجليزية.
المرجع الرسمي: مساعدة LibreOffice: استخدام وظائف Calc في وحدات الماكرو .
كيفية الحكم على ما إذا كان التحسين جيدًا بما فيه الكفاية
| يفحص | علامة جيدة | متى يجب تغيير النهج؟ |
| وقت التشغيل | تكون الجولات المتكررة أقصر باستمرار من خط الأساس. | لا يزال معظم الوقت يُقضى في قسم واحد؛ لذا قم بتحليل هذا القسم بشكل منفصل. |
| الصواب | تتطابق المجاميع وعدد الصفوف والصيغ والسجلات التمثيلية مع الماكرو الأصلي. | يؤدي تحويل المصفوفة إلى تغيير أنواع البيانات أو أبعاد الإخراج. |
| ذاكرة | تتناسب المجموعة الكبيرة بشكل مريح دون الحاجة إلى التبديل أو فترات توقف طويلة في التخصيص. | استخدم أجزاءً أصغر عندما تصبح مصفوفة النطاق الكامل كبيرة جدًا. |
| إعادة الحساب | تتم معالجة الصيغ مرة واحدة بعد التحديث الرئيسي بدلاً من كل عملية كتابة. | تتطلب التبعيات في الصيغ قيمًا وسيطة محسوبة. |
| سلوك واجهة المستخدم | يعود المستند إلى حالة العرض والحساب العادية بعد اكتمال العملية أو فشلها. | أضف إجراءات تنظيف/معالجة أخطاء أقوى إذا كان من الممكن أن تبقى الحالة متغيرة. |
أخطاء شائعة تُفقد الفائدة
- قراءة ورقة عمل كاملة في الذاكرة عندما لا يلزم سوى بضعة أعمدة.
- باستخدام هذه الطريقة
getDataArray()، ولكن مع ذلك يتم كتابة كل نتيجة خليةً خلية.
- تعطيل الحساب التلقائي ونسيان استعادة الإعدادات السابقة.
- وحدات تحكم قابلة للقفل بدون مسار تنظيف موثوق.
- يتم استدعاء النظام
calculateAll()بعد كل دفعة صغيرة حتى عندما تحتاج الخلايا المتسخة فقط إلى إعادة الحساب.
- الحكم على السرعة من خلال جولة واحدة بدلاً من القياسات المتكررة على نفس البيانات.
- تحسين الأداء دون التحقق من بقاء المخرجات متطابقة.
حيث تتوقف هذه التقنيات عن المساعدة
تُقلل عمليات نقل المصفوفات بشكل أساسي من تكلفة الوصول إلى كائنات جداول البيانات، لكنها لا تُصلح خوارزمية مُكلفة بطبيعتها. فعلى سبيل المثال، قد تظل المقارنة المتداخلة لكل صف مع كل صف آخر بطيئة حتى عندما تكون جميع القيم موجودة في الذاكرة. في هذه الحالة، يجب تغيير الخوارزمية: استخدام القواميس أو الفهارس، أو الفرز مرة واحدة بدلاً من الفرز المتكرر، أو تقليل العمل المُكرر، أو نقل عبء العمل إلى أداة معالجة بيانات أكثر ملاءمة عندما لا تُصبح جداول البيانات بيئة التنفيذ المناسبة.
وينطبق الأمر نفسه على وحدات الماكرو التي تهيمن عليها استدعاءات الشبكة، أو استعلامات قواعد البيانات، أو عمليات الإدخال والإخراج للملفات، أو الخدمات الخارجية. قِس أولاً حتى تتمكن من تحسين عنق الزجاجة الفعلي بدلاً من حلقة جدول البيانات الظاهرة.
ترتيب التحسين الموصى به
- قم بقياس الماكرو الحالي باستخدام مجموعة بيانات قابلة للتكرار.
- استبدل عمليات قراءة وكتابة الخلايا المتكررة بمصفوفات النطاق.
- قم بتقييد المعالجة على الصفوف والأعمدة المطلوبة بالضبط.
- استخدم التجزئة إذا كانت المصفوفة الكبيرة كبيرة جدًا بحيث لا يمكن استخدام الذاكرة بشكل مريح.
- قفل وحدات التحكم أثناء عمليات الإنتاج بكميات كبيرة، مع ضمان التنظيف.
- قم بتعليق الحساب التلقائي مؤقتًا عندما يكون تكرار إعادة حساب الصيغة يمثل عائقًا واضحًا.
- أعد الحساب فقط بالقدر اللازم، واستعد حالة التطبيق، وتحقق من المخرجات.
- أعد القياس. إذا كان وقت التشغيل لا يزال يهيمن عليه الحساب بدلاً من الوصول إلى UNO، فقم بتحسين الخوارزمية بدلاً من ذلك.
بالنسبة لمجموعات بيانات Calc الكبيرة، يُعدّ تقليل عدد الاستدعاءات بين كائنات Basic وكائنات جداول البيانات عادةً أهم تحسين هيكلي. تعامل مع كل تحسين إضافي كشيء يُقاس، وليس كإجراء روتيني. لا يكون الماكرو الأسرع مفيدًا إلا إذا ظل صحيحًا، وقابلًا للتنبؤ، وسهل الصيانة.