كيف ملحوظ هو الفرق في الأداء بين تليست, توبجيكتليست, ومجموعة عادي, إذا كان يمكن تقدير?

StackOverflow https://stackoverflow.com/questions/5352021

سؤال

*تلخيص:

يرجى التحقق من التعليقات المطلعة من خبراء دلفي.على وجه التحديد بالنسبة لي ، وأود أن محاولة استخدام تيست القديمة/توبجيكتليست كما اقترح ديفيد ، واستخدام الصلب الزهر و توبجيكتليست.قائمة الممتلكات كما اقترح بوشيز.سأحاول تديناراي عند إعادة بيعها في المستقبل.

=====================================================================

أقول أن لدي TAtom فئة كما هو محدد في التعليمات البرمجية التالية.هناك حوالي hundreds يصل إلى thousands من حالات تاتوم في وقت التشغيل, stored in a dynamic array الى الان.في وقت التشغيل ، ولست بحاجة للقيام الرياضيات تعويم بسيطة على TAtom.X/Y/Z من بين جميع مثيلات تاتوم الموجودة أكثر من 30 مرات في الثانية.

الآن ، ولست بحاجة لإضافة قدرة adding, inserting, deleting من حالات تاتوم في وقت التشغيل.يبدو أن اختياراتي هي (1) طلب مجموعة كبيرة;(2) التمسك مجموعة ديناميكية و سيتلنغث يدويا;(3) قم بالتبديل إلى القائمة العادية;(4) التبديل إلى توبجيكتليست العادية.

أريد تجنب (1) ما لم يكن ذلك ضروريا ، لأنني بعد ذلك يجب أن أغير الكثير من التوقيعات الوظيفية.(2) تبدو ليست جيدة سواء ، لأن تليست/توبجيكتليست يبدو ولد لهذه المهمة.ومع ذلك, لأن هناك حاجة إلى نوع الصب باستخدام تليست العادية/توبجيكتليست, يمكن لبعض تعليق واحد على أداء ممكن ضرب?أعني ، سيكون من الأفضل إذا كان يمكن تقدير عبء الأداء قبل إعادة كتابة التعليمات البرمجية.إذا كان الأداء سينخفض بشكل ملحوظ, هل هناك تقنيات أخرى يمكنني استخدامها?

علاوة على ذلك, أنا أتساءل عما إذا كان هناك فرق في الأداء بين استخدام تليست و توبجكتليست?

  TAtom = class
  public
    ElementZ: Integer;
    X, Y, Z: Extended;  
    other variables: other types;
  end;

  TAAtom = array of TAtom;
هل كانت مفيدة؟

المحلول

إذا كنت تستخدم Generics.Collections.TObjectList<TAtom> وليس هناك حاجة للصب.

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

طالما أنك تتجنب SetLength(A, Length(A)+1) واختيار استراتيجية تخصيص أكثر منطقية صفائف ديناميكية تعادل كل من TList مثل الطبقات.

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

كل شيء إلى حد ما المضاربة وكنت حقا بحاجة لقياس-وإلا يمكننا تخمين فقط.

نصائح أخرى

هل يمكنني إضافة خيار آخر إلى قائمتك?

إذا كنت لا تستخدم أي ميزة الميراث للبيانات في TAtom, ، يمكنك استخدام record بدلا من class.سيتطلب كل مثيل فئة ليتم تخصيصها في الذاكرة ، مليئة الصفر وتهيئتها بشكل فردي. Getmem/Freemem دائما التكلفة ، وسوف تجزئة الذاكرة زيادة.

ديناميكية مخصصة مسبقا array of record سيكون أسرع من مثيلات الفئة الفردية للإضافة.وستكون البيانات مناسبة بشكل أفضل لذاكرة التخزين المؤقت لوحدة المعالجة المركزية إل 1/إل 2.

لإدراج وحذف ، ستكون مجموعة من هذه السجلات أبطأ من TList إذا كان لديك عدد كبير من العناصر ، لأنه سيكون هناك المزيد من البيانات لحذف / إدراج (TList/TObjectList كلاهما يحتفظ بقائمة من المؤشرات فقط).لإدخال / حذف أسرع ، يجب عليك استخدام قائمة مرتبطة بشكل أفضل.

هناك بعض النفقات العامة في TList/TObjectList آلية بسبب الإخطار الداخلي.آلية و GetItem() يمكن أن تكون الخاصية أبطأ قليلا (بسبب فحص النطاق) من استخدام صفيف ديناميكي مباشرة.

ولكن مع شركائنا مجمع تديناراي, ، يمكنك التمسك بصفيف ديناميكي ، ولا يزال لديك أداء جيد ، وميزات التخصيص المسبق ، و TList- مثل الأساليب.وحتى المزيد من الطرق المتاحة ، مثل SaveToStream, Slice, Reverse, ، الفرز مع الفهارس الخارجية وما إلى ذلك...

type
  TAtom = record // could be 'packed record' to save memory (but loose perf)
    ElementZ: Integer;
    X, Y, Z: Extended;  
    other variables: other types;
    // TDynArray also handle complex (e.g. string) types here
  end;
  TAtoms = array of TAtom;

var Atom: TAtom;
    AtomArray: TAtoms;
    AtomCount: integer;
    Atoms: TDynArray;
begin
  Atoms.Init(TypeInfo(TAtoms),AtomArray,@AtomCount);
  Atoms.Capacity := 10000; // pre-allocate array = same as SetLength(AtomArray,10000)
  for i := 1 to 10000 do begin
    A.ElementZ := Random(1000);
    A.X := Random;
    A.Y := Ramdom;
    A.Z := Random;
    // set other fields
    Atoms.Add(A); // fast adding of A properties
  end;
  // you have TList-like methods for your dynamic array
  Atoms.Delete(500); // delete 500th item
  A.ElementZ := 5000;
  Atoms.Insert(500,A); // insert A values at 500th index
  assert(Atoms.Count=10000);
  assert(AtomCount=10000); // same as Atoms.Count
  Atoms.Compare := SortDynArrayInteger;
  Atoms.Sort; // will sort by 1st Integer value = ElementZ
  for i := 1 to Atoms.Count-1 do // or AtomCount-1
    // you have still direct access to AtomArray[]
    // -> this is even the fastest access to the data
    assert(AtomArray[i].ElementZ >=AtomArray[i-1].ElementZ )
  Atoms.SaveToStream(aStream); // will also save any string content
  Atoms.Reverse; // reverse all items order
  Atoms.Clear;
  // faster adding will be done with direct access to the dynamic array
  Atom.Count := 10000; // allocate memory for 10000 items
  for i := 0 to 10000-1 do
  with AtomArray[i] do
  begin
    ElementZ := Random(2000);
    X := Random;
    Y := Random;
    Z := Random;
  end;
  Atoms.Sort; // TDynArray knows about the data just created
end; // no need to have any try...finally ..Free block

يعمل مع دلفي 6 تصل إلى ز.

مع الإصدار الأحدث من دلفي دعم الأدوية ، يجب أن تذهب بشكل أفضل في هذا الاتجاه.

ومع ذلك ، لأن نوع الصب هو مطلوب باستخدام العادية تيست / توبجيكتليست ، يمكن لبعض واحد التعليق على الأداء المحتمل ضرب?

إذا قمت بكتابة المصبوب باستخدام النموذج

List[I] as TAtom

كما سيتم إضافة النفقات العامة الصغيرة ، والتي يمكن أن تضيف حقا في وضعك.ومع ذلك ، إذا كنت من الصعب التلبيس

TAtom(List[I])

بقدر ما أعرف ، لا النفقات العامة يحدث في الواقع كما يتم تنفيذ التلبيس دون الشيكات وأعتقد أيضا يتم ذلك في وقت الترجمة.

أما بالنسبة للجانب الآخر من سؤالك ، وأعتقد أنها قد تم تغطيتها بشكل صحيح بالفعل...

كما توبجيكتليست هو سليل مباشر من تيليست العروض ستكون قريبة جدا.

السؤال الأول:هل نتحدث عن Classes.TList و Contnrs.TObjectList أم أننا نتحدث عن Generics.Collections.TList على التوالي Generics.Collections.TObjectList ?

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


إذا كنا نتحدث عن "كبار السن" TList و TObjectList, ، ثم نحن بحاجة للمقارنة فقط TList مع المصفوفة الديناميكية المكافئة ، منذ ذلك الحين TObjectList هو سليل TList لذلك يرث كل خصائص الأداء. TList يستخدم كتلة من الذاكرة المخصصة باستخدام ReallocMem.الصفيف الديناميكي يفعل نفس الشيء داخليا ، لذلك لا ينبغي أن يكون هناك فرق كبير!

خاتمة

إذا كان هناك أي فرق في الأداء بين الاثنين ، فمن المحتمل أن يكون ذلك بسبب الاستخدام الساذج للمصفوفة الديناميكية يستخدم اللعين SetLength(A, Length(A)+1), ، في حين أن التنفيذ الأفضل في جميع الحاويات المقدمة دلفي قبل تخصيص الذاكرة في أجزاء أكبر.مع التعليمات البرمجية المناسبة لا ينبغي أن يكون هناك أي فرق كبير بين تلك البديل!

قم بعمل مشروع اختبار وقياس وقت إضافة وإدراج وحذف الآلاف من مثيلات تاتوم باستخدام الطرق الأربعة.ثم تقرر أي واحد لاستخدام.

تيست و توبجيكتليست ربما أسرع من مجموعة ديناميكية عند إضافة ، إدراج وحذف ، لأن مجموعة ديناميكية باستمرار يجب إعادة تخصيصها.تنفيذ تليست و توبجكتليست لا تفعل ذلك.

TList الخ.هل بالضبط ما رمز العمل على أجزاء من الذاكرة أو ديناريز يجب أن تفعل ، ولكن تنفيذها هو الأمثل بالفعل للحالة المشتركة ، ويتضمن اعتبارات حول كيفية سلوك مدير الذاكرة.

يمكن أن يكون أحد المعايير هو نسبة القراءات / التحديثات إلى التسلسل.إذا تم تحديث التسلسل بشكل غير منتظم بعد إنشائه ، فيجب أن تكون هناك سرعة أفضل يمكن إدراكها باستخدام الدينارات ، لأن الوصول إلى العناصر باستخدام TList ويتطلب الإعجابات استدعاء طريقة واحدة بالإضافة إلى التحقق من الحدود ، بالإضافة إلى التحقق من النوع إذا كنت تستخدم as المشغل.

في النهاية ، فإن تكلفة الحساب القيام به على TAtom يجب أن تهيمن على وقت التشغيل ، مما يجعل اختيار ديناراي أو TListXXX غير ذي صلة.

سيكون للمصفوفات الديناميكية للسجلات أقل تأثير عند الوصول إلى العناصر ، إذا كانت ذراتك كائنات ، فستكون جميع القوائم مكافئة إلى حد ما من حيث سرعة الوصول.

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

  • قائمة مرتبطة إذا لم تكن بحاجة إلى الوصول إلى الذرات حسب الفهرس
  • شجرة ، يجب أن يكون لديك استخدام لتقسيم الفضاء من الذرات الخاصة بك ، قد تستخدم كذلك هذا القسم لعقد الذرات الخاصة بك بدلا من مجموعة
  • السماح بعناصر غير محددة / لا شيء في صفيفك / قائمتك ، والحفاظ على مجموعة من العناصر غير المحددة/لا شيء ، وفهرس إذا كنت بحاجة إلى قائمة مرتبة (من المحتمل أن تكون الحل الأعلى أداء ، ولكن من المحتمل أيضا أن تكون الأكثر تعقيدا من حيث الكفاءة)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top