لقد تم زيادة مصطلح "مقياس الويب" مؤخرًا ، كما أن الناس يجعلون أنظمتهم أكثر "مجالًا واسعًا" عن طريق توسيع بنية التطبيق الخاصة بهم. ولكن ما هو بالضبط مجال كامل؟ أو كيفية ضمان المجال بأكمله؟
حمولة التحجيم الأكثر فترات هي المجال الأكثر شعبية. على سبيل المثال ، يمكن أن تدعم الأنظمة التي تدعم وصول المستخدم الفردي أيضًا 10 أو 100 أو حتى مليون مستخدم. من الناحية المثالية ، يجب أن يظل نظامنا "عديمي الجنسية" قدر الإمكان. حتى إذا كان يجب أن تكون هناك حالة ، فيمكن تحويلها ونقلها على محطات معالجة مختلفة للشبكة. عندما يصبح الحمل عنق الزجاجة ، قد لا يكون هناك تأخير. لذلك للحصول على طلب واحد ، من المقبول أن يستغرق 50 إلى 100 ميلي ثانية. وهذا ما يسمى التحجيم.
يعمل الامتداد بشكل مختلف تمامًا في تحسين المجال الكامل. على سبيل المثال ، يمكن لخوارزمية تضمن أن بيانات واحدة تتم معالجتها بنجاح يمكن أيضًا معالجة 10 أو 100 أو حتى مليون بيانات. تعقيد الحدث (رموز O الكبيرة) هو أفضل وصف بغض النظر عما إذا كان هذا النوع المتري ممكن أم لا. الكمون هو قاتل تحجيم الأداء. سوف تبذل قصارى جهدك لمعالجة جميع العمليات على نفس الجهاز. وهذا ما يسمى التحجيم.
إذا كان بإمكان الفطيرة أن تسقط من السماء (بالطبع هذا أمر مستحيل) ، فقد نكون قادرين على الجمع بين التوسع الأفقي والتوسع الرأسي. ومع ذلك ، لن نقدم اليوم فقط الطرق البسيطة التالية لتحسين الكفاءة.
كل من Forkjoinpool في Java 7 ودفقات البيانات المتوازية في Java 8 (Parallelsstream) مفيدة للمعالجة الموازية. من الواضح بشكل خاص عند نشر برامج Java على المعالجات متعددة النواة ، حيث يمكن لجميع المعالجات الوصول إلى نفس الذاكرة.
لذلك ، فإن الفائدة الأساسية لهذه المعالجة المتوازية هي القضاء على الكمون تقريبًا مقارنةً بالتوسيع على الأجهزة المختلفة عبر الشبكات.
لكن لا تخلط بين آثار المعالجة المتوازية! يرجى مراعاة النقطتين التاليتين:
إن تقليل تعقيد الخوارزمية هو بلا شك الطريقة الأكثر فعالية لتحسين الأداء. على سبيل المثال ، بالنسبة لأسلوب مثيل HashMAP ، فإن تعقيد الأحداث O (1) أو تعقيد الفضاء O (1) هي الأسرع. لكن هذا الموقف غالبًا ما يكون مستحيلًا ، ناهيك عن تحقيقه بسهولة.
إذا لم تتمكن من تقليل تعقيد الخوارزمية ، فيمكنك أيضًا تحسين الأداء من خلال إيجاد نقاط رئيسية في الخوارزمية وتحسين الأساليب. لنفترض أن لدينا مخطط الخوارزمية التالية:
التعقيد العام العام لهذه الخوارزمية هو O (N3) ، وإذا تم حسابه في ترتيب وصول منفصل ، فيمكن أيضًا استنتاج أن التعقيد هو O (n x o x p). ولكن على أي حال ، سنجد بعض السيناريوهات الغريبة عندما نحلل هذا الرمز:
بدون مرجع بيانات الإنتاج ، قد نستخلص بسهولة استنتاجات مفادها أنه يجب علينا تحسين "العمليات ذات الرأس العالي". لكن التحسينات التي قمنا بها لم يكن لها أي تأثير على المنتجات التي يتم تسليمها.
القاعدة الذهبية المحسنة ليست أكثر من ما يلي:
هذا كل شيء للنظرية. على افتراض أننا وجدنا أن المشكلة تحدث في الفرع الصحيح ، فمن المحتمل أن المعالجة البسيطة في المنتج تفقد الاستجابة بسبب قدر كبير من الوقت (على افتراض أن قيم N و O و P كبيرة جدًا) ، يرجى ملاحظة أن التعقيد الزمني للفرع الأيسر المذكور في المقالة هو O (N3). لا يمكن تمديد الجهود المبذولة هنا ، ولكن يمكن أن توفر الوقت للمستخدمين وتأخير تحسينات الأداء الصعبة حتى وقت لاحق.
فيما يلي 10 نصائح لتحسين أداء Java:
1. استخدم StringBuilder
يجب استخدام StingBuilder افتراضيًا في رمز Java الخاص بنا ، ويجب تجنب المشغل +. ربما سيكون لديك آراء مختلفة حول سكر بناء الجملة من StringBuilder ، مثل:
String x = "a" + args.length + "b" ؛
سيتم تجميعها على النحو التالي:
0 New Java.lang.StringBuilder [16] 3 DUP4 LDC <String "A"> [18] 6 invokespecial java.lang.stringbuilder (java.lang.string) [20] 9 aload_0 [args] java.lang.stringbuilder [23] 14 ldc <string "b"> [27] 16 Invokevirtual java.lang.stringbuilder.append (java.lang.string): java.lang.stringbuilder [29] [32] 22 Store_1 [X]
لكن ماذا حدث بالضبط؟ هل تحتاج إلى استخدام الأقسام التالية لتحسين السلسلة التالية؟
string x = "a" + args.length + "b" ؛ if (args.length == 1) x = x + args [0] ؛
لقد استخدمنا الآن سلسلة StringBuilder الثانية ، والتي لا تستهلك ذاكرة إضافية في الكومة ، ولكنها تضع الضغط على GC.
StringBuilder x = new StringBuilder ("a") ؛ x.append (args.length) ؛ x.append ("b") ؛ if (args.length == 1) ؛ x.append (args [0]) ؛في المثال أعلاه ، إذا كنت تعتمد على برنامج التحويل البرمجي Java لإنشاء المثيل ضمنيًا ، فإن التأثير المترجم ليس له علاقة بما إذا كان يتم استخدام مثيل StringBuilder. يرجى تذكر: في فرع NOPE ، يتم إنفاق الوقت الذي يقضيه في كل دورة CPU على GC أو تخصيص مساحة افتراضية لـ StringBuilder ، ونحن نضيع وقتًا.
بشكل عام ، يعد استخدام StringBuilder أفضل من استخدام عامل التشغيل +. إذا كان ذلك ممكنًا ، حدد StringBuilder إذا كنت بحاجة إلى تمرير المراجع عبر طرق متعددة ، لأن السلسلة تستهلك موارد إضافية. يستخدم Jooq هذه الطريقة عند إنشاء عبارات SQL المعقدة. يتم استخدام stringBuilder واحد فقط خلال تمرير SQL بالكامل من شجرة بناء الجملة المجردة.
الأمر الأكثر مأساوية هو أنه إذا كنت لا تزال تستخدم StringBuffer ، فاستخدم StringBuilder بدلاً من StringBuffer. بعد كل شيء ، لا توجد في الحقيقة العديد من الحالات التي تحتاج إلى مزامنة السلاسل.
تعطي التعبيرات العادية للناس انطباعًا بأنهم سريع وسهل. لكن استخدام التعبيرات العادية في فرع NOPE سيكون أسوأ قرار. إذا كان عليك استخدام تعبيرات منتظمة في التعليمات البرمجية المكثفة ، على الأقل قم بتخزين النمط لتجنب تجميع النمط بشكل متكرر.
نمط نهائي ثابت Heavy_regex = pattern.compile ("((((x)*y)*z)*") ؛إذا تم استخدام تعبير منتظم بسيط مثل ما يلي:
String [] parts = ipaddress.split ("//.") ؛من الأفضل استخدام صفيف char [] أو التشغيل القائم على الفهرس. على سبيل المثال ، يلعب الرمز التالي مع قابلية القراءة الضعيفة نفس الدور.
int length = ipaddress.length () ؛ int roffset = 0 ؛ int part = 0 ؛ for (int i = 0 ؛ i <length ؛ i ++) {if (i == length - 1 || ipaddress.charat (i+1) == '.'يوضح الرمز أعلاه أيضًا أن التحسين المبكرة لا معنى له. على الرغم من مقارنة طريقة split () ، فإن هذا الرمز أقل قابلية للصيانة.
التحدي: هل يمكن للأصدقاء الأذكياء التوصل إلى خوارزميات أسرع؟
تعتبر التعبيرات العادية مفيدة للغاية ، ولكن عليها أيضًا دفع ثمن عند استخدامها. خاصة عندما تكون عميقًا في فروع كلا ، يجب عليك تجنب استخدام التعبيرات العادية بأي ثمن. كن حذرًا أيضًا من طرق سلسلة JDK المختلفة التي تستخدم التعبيرات العادية ، مثل string.replaceall () أو string.split (). يمكنك اختيار استخدام مكتبة تطوير أكثر شعبية ، مثل Apache Commons Lang ، لتنفيذ عمليات السلسلة.
لا ينطبق هذا الاقتراح على المناسبات العامة ، ولكن فقط على السيناريوهات بعمق في فرع NOPE. ومع ذلك ، يجب أن تفهم شيئًا. طريقة كتابة حلقة تنسيق Java 5 مريحة للغاية بحيث يمكننا أن ننسى طريقة الحلقة الداخلية ، مثل:
لـ (قيمة السلسلة: سلاسل) {// افعل شيئًا مفيدًا هنا}كلما تم تشغيل الرمز إلى هذه الحلقة ، إذا كان متغير السلاسل أمرًا لا يتجزأ ، فسيقوم الرمز تلقائيًا بإنشاء مثيل للمترجمة. إذا كنت تستخدم ArrayList ، فسيقوم الجهاز الظاهري تلقائيًا بتخصيص 3 ذاكرة نوع عدد صحيح للكائن على الكومة.
الطبقة الخاصة ITR تنفذ iterator <e> {int arsor ؛ int lastret = -1 ؛ int equiventModCount = modCount ؛ // ...يمكنك أيضًا استخدام طريقة الحلقة المكافئة التالية لاستبدال ما ورد أعلاه للحلقة ، فقط "إهدار" قطعة من الجراحة التجميلية على المكدس ، وهي فعالة من حيث التكلفة.
int size = strings.size () ؛ for (int i = 0 ؛ i <size ؛ i ++) {string value: strings.get (i) ؛ // افعل شيئًا مفيدًا هنا}إذا لم تتغير قيمة السلسلة في الحلقة كثيرًا ، فيمكنك أيضًا استخدام المصفوفات لتنفيذ الحلقة.
لـ (قيمة السلسلة: StringArray) {// افعل شيئًا مفيدًا هنا}سواء من منظور القراءة والكتابة السهلة ، أو من منظور تصميم واجهة برمجة التطبيقات (API) ، فإن المتكررين ، والواجهات الرائعة ، وحلقات فورتش مفيدة للغاية. ولكن في التكلفة ، عند استخدامها ، يتم إنشاء كائن إضافي على الكومة لكل طفل حلقة. إذا تم تنفيذ الحلقة عدة مرات ، فيرجى توخي الحذر لتجنب توليد حالات لا معنى لها. من الأفضل استخدام طريقة حلقة المؤشر الأساسية لاستبدال المتكرر المذكور أعلاه ، واجهة ITERBAL و FOREACH.
وتناقش بعض الآراء التي تعترض على ما ورد أعلاه (وخاصة استبدال المتكررين مع المؤشرات) على Reddit للحصول على التفاصيل.
بعض الطرق باهظة الثمن. أخذ فرع NOPE كمثال ، لم نذكر الطرق ذات الصلة للأوراق ، ولكن يمكن العثور على هذا واحد. لنفترض أن برنامج تشغيل JDBC الخاص بنا يحتاج إلى التغلب على جميع الصعوبات لحساب قيمة الإرجاع لطريقة resultset.wasnull (). قد يبدو إطار SQL الذي ننفذه أنفسنا مثل هذا:
if (type == integer.class) {result = (t) wasnull (rs ، integer.valueof (rs.getint (index))) ؛} // ثم ... نهائي ثابت <T> t wasnull (resultset rs ، t value) tows sqlexception {return rs.wasnull ()؟ NULL: القيمة ؛}في المنطق أعلاه ، يتم استدعاء طريقة resultset.wasnull () في كل مرة يتم الحصول على قيمة int من مجموعة النتائج ، ولكن يتم تعريف طريقة getInt () على أنها:
نوع الإرجاع: قيمة متغيرة ؛ إذا كانت نتيجة استعلام SQL خالية ، فالتراجع 0.
لذا فإن طريقة بسيطة وفعالة لتحسينها هي على النحو التالي:
static النهائي <t يمتد الرقم> t wasnull (resultset rs ، t value) يلقي sqlexception {return (value == null || (value.intvalue () == 0 && rs.wasnull ()))؟ NULL: القيمة ؛}هذا نسيم.
تستدعي طريقة ذاكرة التخزين المؤقت لاستبدال الطرق العلوية العالية على عقد الأوراق ، أو تجنب استدعاء طرق النفقات العامة العالية إذا سمحت اتفاقية الطريقة.
يقدم ما ورد أعلاه استخدام عدد كبير من الأدوية الجنيسة في المثال من JOOQ ، مما يؤدي إلى استخدام فئات البايت ، و int ، والغلاف الطويل. ولكن على الأقل يجب ألا تكون الأدوية قيودًا على رمز حتى يتم تخصصها في مشاريع Java 10 أو Valhalla. لأنه يمكن استبداله بالطريقة التالية:
// المخزنة على عدد صحيح الكومة I = 817598 ؛
... إذا كتبت بهذه الطريقة:
// store on the stack int i = 817598 ؛
يمكن أن تزداد الأمور سوءًا عند استخدام المصفوفات:
// تم إنشاء ثلاثة كائنات على عدد صحيح الكومة [] i = {1337 ، 424242} ؛... إذا كتبت بهذه الطريقة:
// يتم إنشاء كائن واحد فقط على الكومة int [] i = {1337 ، 424242} ؛عندما نكون عميقين في فرع NOPE ، يجب أن نبذل قصارى جهدنا لتجنب استخدام فصول التغليف. الجانب السلبي من القيام بذلك هو أنه يضع الكثير من الضغط على GC. ستكون GC مشغولة جدًا بمسح الكائنات التي تم إنشاؤها بواسطة فئة التغليف.
لذلك تتمثل طريقة التحسين الفعالة في استخدام أنواع البيانات الأساسية ، والمصفوفات ذات الطول الثابت ، واستخدام سلسلة من متغيرات الانقسام لتحديد موضع الكائن في الصفيف.
TROVE4J ، التي تتبع بروتوكول LGPL ، هي مكتبة فئة جمع Java ، والتي توفر لنا تنفيذ أداء أفضل من صفيف تشكيل int [].
الاستثناء التالي لهذه القاعدة: لأن أنواع Boolean و Byte ليست كافية للسماح لـ JDK بتوفير طريقة ذاكرة التخزين المؤقت لذلك. يمكننا الكتابة بهذه الطريقة:
منطقية A1 = صواب ؛ // ... Syntax Sugar for: boolean a2 = boolean.valueof (true) ؛ byte b1 = (byte) 123 ؛ // ... Syntax Sugar for: byte b2 = byte.valueof ((byte) 123) ؛
الأنواع الأساسية الأخرى من الأعداد الصحيحة لديها أيضًا حالات متشابهة ، مثل Char و Short و Int و Long.
لا تقم تلقائيًا بتوصيل هذه الأنواع البدائية الصحيح عند استدعاء المُنشئين أو استدعاء طريقة thetype.valueof ().
لا تتصل أيضًا بمنشئات على فصول الغلاف إلا إذا كنت ترغب في الحصول على مثيل لم يتم إنشاؤه على الكومة. ميزة القيام بذلك هي أن تمنحك نكتة يوم كذبة أبريل الضخمة لزملائك.
بالطبع ، إذا كنت ترغب في تجربة مكتبة الوظائف خارج الرثة ، على الرغم من أن هذا قد يتم خلطه مع الكثير من القرارات الاستراتيجية ، بدلاً من الحل المحلي الأكثر تفاؤلاً. للحصول على مقالة مثيرة للاهتمام حول التخزين غير الرمش الذي كتبه بيتر لوري وبن كوتون ، يرجى النقر فوق: OpenJdk و Hashmap-دع المحاربين القدامى يتقنون تقنيات جديدة بأمان (تخزين غير مركزين!).
في الوقت الحاضر ، تشجع لغات البرمجة الوظيفية مثل سكالا العودية. نظرًا لأن العودية تعني عادةً أن تحلل الذيل يمكن أن يتحلل إلى أفراد محسنين بشكل فردي. سيكون من الأفضل إذا كانت لغة البرمجة التي تستخدمها يمكن أن تدعمها. ولكن رغم ذلك ، كن حذرًا من أن التعديل الطفيف للخوارزمية سيحول عودية الذيل إلى عودية عادية.
نأمل أن يتمكن المترجم من اكتشاف هذا تلقائيًا ، وإلا فإننا كنا نضيع الكثير من إطارات المكدس للأشياء التي يمكن القيام بها مع عدد قليل من المتغيرات المحلية.
لا يوجد شيء يمكن قوله في هذا القسم ، إلا أن التكرار قدر الإمكان في فرع NOPE بدلاً من العودية.
عندما نريد التكرار على خريطة تم حفظها في أزواج القيمة الرئيسية ، يجب أن نجد سببًا جيدًا للرمز التالي:
لـ (K Key: map.keyset ()) {v value: map.get (key) ؛}ناهيك عن طريقة الكتابة التالية:
لـ (إدخال <k ، v> الإدخال: map.entryset ()) {k key = entrate.getKey () ؛ v value = interph.getValue () ؛}عندما نستخدم فرع NOPE ، يجب أن نستخدم الخريطة بحذر. نظرًا لأن العديد من عمليات الوصول التي يبدو أن لديها تعقيد زمني لـ O (1) تتكون بالفعل من سلسلة من العمليات. والوصول نفسه ليس مجانيا. على الأقل ، إذا كان عليك استخدام الخريطة ، فأنت بحاجة إلى استخدام طريقة الإدخال () للتكرار! وبهذه الطريقة ، نريد فقط الوصول إلى مثيل الخريطة.
عندما يكون من الضروري التكرار على الخريطة في شكل أزواج القيمة الرئيسية ، تأكد من استخدام طريقة الإدخال ().
8. استخدم enumset أو enummap
في بعض الحالات ، مثل استخدام خريطة التكوين ، قد نعرف مسبقًا القيمة الرئيسية المحفوظة في الخريطة. إذا كانت هذه القيمة الرئيسية صغيرة جدًا ، فيجب علينا التفكير في استخدام Enumset أو Enummap بدلاً من استخدام Hashset أو HashMap الذي نستخدمه عادة. الرمز التالي يعطي شرحًا واضحًا:
كائن عابر خاص [] vals ؛ public v put (k key ، v value) {// ... int index = key.ordinal () ؛ vals [index] = masknull (value) ؛ // ...}إن التنفيذ الرئيسي للرمز السابق هو أننا نستخدم المصفوفات بدلاً من جداول التجزئة. خاصة عند إدخال قيم جديدة في الخريطة ، كل ما عليك فعله هو الحصول على رقم تسلسل ثابت تم إنشاؤه بواسطة برنامج التحويل البرمجي لكل نوع التعداد. إذا كان هناك تكوين خريطة عالمي (على سبيل المثال ، مثيل واحد فقط) ، ستحقق ENUMMAP أداءً أكثر إمتاعًا من HashMap تحت ضغط زيادة سرعة الوصول. والسبب هو أن ENUMMAP يستخدم ذاكرة واحدة أقل من الكومة من HashMap ، وأن HashMap يستدعي طريقة hashcode () وطريقة متساوية () في كل قيمة مفتاح.
ENUM و ENUMMAP صديقان مقربون. عندما نستخدم القيم الرئيسية المشابهة للهياكل التي تشبه التعداد ، يجب أن نفكر في إعلان هذه القيم الرئيسية كأنواع التعداد واستخدامها كمفاتيح Enummap.
في حالة عدم استخدام ENUMMAP ، يجب تحسين طرق HashCode () ومتساوية () على الأقل. طريقة hashcode () جيدة هي ضرورية لأنها تمنع المكالمات غير الضرورية إلى طريقة () equals ().
في بنية الميراث لكل فئة ، هناك حاجة إلى كائنات بسيطة مقبولة بسهولة. دعونا نلقي نظرة على كيفية تطبيق org.jooq.table من Jooq؟
إن أبسط وأسرع طريقة تنفيذ Hashcode () هي كما يلي:
. return name.hashcode () ؛}
الاسم هو اسم الجدول. لا نحتاج حتى إلى النظر في المخطط أو سمات الجدول الأخرى ، لأن أسماء الجدول عادة ما تكون فريدة من نوعها في قاعدة البيانات. والاسم المتغير عبارة عن سلسلة ، والتي قامت بالفعل بتخزين قيمة hashcode ().
تعتبر التعليقات في هذا الرمز مهمة للغاية لأن AbstractTable الموروث من AbstractQueryPart هو التنفيذ الأساسي لأي عنصر شجرة بناء الجملة المجردة. لا تحتوي عناصر شجرة بناء الجملة العادية على أي سمات ، لذلك لا يمكن أن يكون لها أي خيال حول تحسين تطبيق طريقة HashCode (). طريقة hashcode () مكتوبة فوقها هي كما يلي:
. // يجب أن تتجاوز الفئة الفرعية للتنفيذ المحددة هذه الطريقة لتحسين الأداء. Return Create (). RenderInlined (this) .hashCode () ؛}
وبعبارة أخرى ، يتم تشغيل سير عمل SQL بأكمله لحساب رمز التجزئة لعنصر شجرة بناء الجملة المجردة العادية.
طريقة equals () أكثر إثارة للاهتمام:
. if (that extureoftable) {if (stringUtils.equals (name ، (((ustructiontable <؟>) that) .Name)))) {return super.equals (that) ؛أولاً ، لا تستخدم طريقة متساوية () في وقت مبكر جدًا (ليس فقط في كلا) ، إذا:
ملاحظة: إذا استخدمنا مثيلًا في وقت مبكر للغاية للتحقق من الأنواع المتوافقة ، فإن الشروط التالية تتضمن بالفعل وسيطة == NULL. لقد شرحت هذا بالفعل في مدونتي السابقة ، يرجى الرجوع إلى 10 أفضل ممارسات ترميز Java الرائعة.
بعد أن انتهت مقارنة الحالات المذكورة أعلاه ، يجب أن نكون قادرين على استخلاص بعض الاستنتاجات. على سبيل المثال ، يتم استخدام طريقة Table.equals () من JOOQ لمقارنة ما إذا كان الجدولين متماثلين. بغض النظر عن نوع التنفيذ المحدد ، يجب أن يكون لديهم نفس اسم الحقل. على سبيل المثال ، لا يمكن أن يكون العنصران التاليان هو نفسه:
إذا استطعنا بسهولة تحديد ما إذا كانت المعلمة الواردة مساوية للمثال نفسه (هذا) ، فيمكننا التخلي عن العملية إذا كانت النتيجة خاطئة. إذا كانت نتيجة الإرجاع صحيحة ، فيمكننا زيادة الحكم على التنفيذ الفائق لفئة الوالدين. في الحالة التي لا تساوي فيها معظم الكائنات المقارنة ، يمكننا إنهاء الطريقة في أقرب وقت ممكن لحفظ وقت تنفيذ وحدة المعالجة المركزية.
بعض الأشياء لها تشابه أعلى من غيرها.
في Jooq ، يتم إنشاء معظم مثيلات الجدول بواسطة مولد رمز Jooq ، وقد تم تحسين طريقة Equals () لهذه الحالات بعمق. العشرات من أنواع الجدول الأخرى (الجداول المشتقة) ، وظائف قيمة الجدول ، جداول الصفيف ، الجداول المرتبطة ، الجداول المحورية ، تعبيرات الجدول الشائعة ، وما إلى ذلك ، الحفاظ على التنفيذ الأساسي لطريقة متساوية ().
أخيرًا ، هناك موقف آخر يمكن تطبيقه على جميع اللغات وليس فقط Java. بالإضافة إلى ذلك ، سيكون فرع NOPE الذي درسناه سابقًا أيضًا مفيدًا في الفهم من O (N3) إلى O (n log n).
لسوء الحظ ، يستخدم العديد من المبرمجين خوارزميات محلية بسيطة للنظر في المشكلة. يتم استخدامها لحل المشكلات خطوة بخطوة. هذا هو شكل "نعم/أو" من الحتمية. من السهل تصميم نمط البرمجة "صورة أكبر" عند التحويل من البرمجة الضرورية الخالصة إلى البرمجة الموجهة للكائن إلى البرمجة الوظيفية ، ولكن هذه الأنماط تفتقر إلى ما هو موجود فقط في SQL و R: R:
برمجة التصريح.
في SQL ، يمكننا أن نعلن التأثير المطلوب لقاعدة البيانات دون النظر في تأثير الخوارزمية. يمكن أن تعتمد قاعدة البيانات أفضل خوارزمية وفقًا لنوع البيانات ، مثل القيود والمفاتيح والفهارس ، إلخ.
من الناحية النظرية ، كان لدينا أولاً أفكار أساسية بعد SQL والحسابات العلائقية. في الممارسة العملية ، قام بائعو SQL بتنفيذ مُحسِّنات فعالة قائمة على النفقات العامة (محسّنات قائمة على التكلفة) على مدار العقود القليلة الماضية. ثم في إصدار 2010 ، اكتشفنا أخيرًا كل إمكانات SQL.
لكننا لسنا بحاجة إلى تنفيذ SQL باستخدام طريقة SET. تدعم جميع اللغات والمكتبات مجموعات ومجموعات وأكياس وقوائم. الفائدة الرئيسية لاستخدام SET هي أنه يمكن أن يجعل الكود الخاص بنا موجزًا وواضحًا. على سبيل المثال ، طريقة الكتابة التالية:
Someset تتقاطع مع بعض الأمهات
بدلاً من
// طريقة الكتابة السابقة لـ Java 8 Set Result = new Hashset () ؛ بالنسبة إلى (مرشح الكائن: someset) إذا (بعض الأمهات.
قد يكون لدى بعض الأشخاص آراء مختلفة حول البرمجة الوظيفية وجافا 8 التي يمكن أن تساعدنا في كتابة خوارزميات أبسط وأبسط. لكن هذا الرأي ليس صحيحًا بالضرورة. يمكننا تحويل حلقة Java 7 الضرورية إلى مجموعة Stream Java 8 ، لكننا ما زلنا نستخدم نفس الخوارزمية. لكن تعبيرات على غرار SQL مختلفة:
Someset تتقاطع مع بعض الأمهاتيمكن أن يكون للرمز أعلاه 1000 تطبيق مختلف على محركات مختلفة. ما ندرسه اليوم هو تحويل مجموعتين إلى enumset تلقائيًا قبل استدعاء عملية التقاطع. حتى يمكننا إجراء عمليات متوازية متوازية دون استدعاء البث الأساسي.
في هذه المقالة ، نناقش التحسينات حول المتفرعة. على سبيل المثال ، في أعماق خوارزميات عالية المعقدة. كمطورين لـ Jooq ، يسعدنا تحسين جيل SQL.
يقع Jooq في "أسفل السلسلة الغذائية" لأنه آخر واجهة برمجة التطبيقات التي يطلق عليها برنامج الكمبيوتر الخاص بنا عند مغادرة JVM وإدخال DBMs. يقع في الجزء السفلي من السلسلة الغذائية أن أي خط يستغرق وقتًا عند تنفيذه في Jooq ، لذلك أريد تحسينه في أقرب وقت ممكن.
قد لا يكون منطق أعمالنا معقدًا مثل فرع Nope. ومع ذلك ، قد يكون الإطار الأساسي معقدًا للغاية (إطار SQL المحلي ، والمكتبات المحلية ، وما إلى ذلك). لذلك ، نحتاج إلى اتباع المبادئ المذكورة اليوم ، ونستخدم التحكم في مهمة Java أو أدوات أخرى للتحقق مما إذا كان هناك أي مجال يحتاج إلى تحسين.
الرابط الأصلي: Jaxenter Translation: ImportNew.com - دائمًا على رابط ترجمة الطريق: http://www.importnew.com/16181.html