يمكن تعداده: كيفية الحصول على قيمة العمل

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

للتظاهر بالأفكار ، في المقالة سوف تستخدم لغة C # ، ولكن قد يتم ترجمة معظم الأفكار إلى لغات أخرى.

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

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

مثال المهمة:

  1. تحميل byline مجموعة من السجلات من ملف أو DB في الذاكرة.
  2. لكل عمود في السجل ، قم بتغيير القيمة إلى قيمة أخرى لشخص ما.
  3. احفظ نتائج التحول إلى ملف أو DB.

لنفترض عدة حالات قد يكون فيها هذا المنطق قابلاً للتطبيق. في هذه اللحظة ، أرى حالتين:

  1. ربما يكون جزء من التدفق لبعض تطبيقات ETL وحدة التحكم.
  2. ربما يكون منطق داخلي للعمل في تطبيق المراقب من MVC.

إذا قمنا بإعادة صياغة المهمة بطريقة تقنية أكثر ، فقد يبدو الأمر كالتالي: "(1) خصص مقدارًا من الذاكرة ، (2) قم بتحميل المعلومات في الذاكرة من تخزين الثبات ، (3) تعديل و (4) سجلات التدفق التغييرات في الذاكرة إلى تخزين الثبات. " هنا العبارة الأولى في الوصف "(1) تخصيص مقدار من الذاكرة" قد يكون لها علاقة حقيقية بمتطلباتك غير الوظيفية. نظرًا لأن وظيفتك / خدمتك يجب أن "تعيش" في بعض بيئة الاستضافة التي قد يكون لها بعض القيود / القيود (على سبيل المثال ، 150 ميغابايت لكل خدمة صغيرة) وللتنبؤ بالإنفاق على خدمتك في الميزانية ، يجب أن نتوقع ، في حالتنا ، مقدار الذاكرة ما الخدمة التي ستستخدمها (عادة ما نقول عن الحد الأقصى لمقدار الذاكرة). بمعنى آخر ، يجب أن نحدد "بصمة" الذاكرة لخدمتك.

دعنا نفكر في بصمة الذاكرة للتنفيذ الشائع حقًا الذي ألاحظه من وقت لآخر في قواعد بيانات مختلفة لمشاريع المؤسسة. أيضًا ، يمكنك محاولة العثور عليه في مشاريعك أيضًا ، على سبيل المثال ، "تحت غطاء" تطبيق نمط "مستودع التخزين" ، حاول فقط العثور على مثل هذه الكلمات: "قائمة" ، "ToArray" ، "ToReadonlyCollection" وغيرها. كل هذا التنفيذ يعني:

1. لكل سطر / سجل في ملف / db ، يخصص ذاكرة للاحتفاظ بخصائص السجل من ملف / ديسيبل (على سبيل المثال var user = مستخدم جديد () {FirstName = 'Test' ، LastName = 'Test2'})

2. بعد ذلك ، بمساعدة ، على سبيل المثال ، "ToArray" أو يدويًا ، يتم الاحتفاظ بمراجع الكائن في بعض المجموعات (على سبيل المثال var المستخدمين = قائمة جديدة () ؛ users.Add (مستخدم)). لذلك ، يتم تخصيص مقدار معين من الذاكرة لكل سجل من ملف وعدم نسيانه ، يتم تخزين المرجع في بعض المجموعات.

هنا مثال:

private static IEnumerable<User> LoadUsers2() { var list = new List<User>(); foreach(var line in File.ReadLines("text.txt")) { var splittedLine = line.Split(';'); list.Add(new User() { FirstName = splittedLine[0], LastName = splittedLine[1] }); } return list; // or return File.ReadLines("text.txt") .Select(line => line.Split(';')) .Select(splittedLine => new User() { FirstName = splittedLine[0], LastName = splittedLine[1] }).ToArray(); } 

نتائج ملفات تعريف الذاكرة:

صورة

بالضبط مثل هذه الصورة التي رأيتها في كل مرة في بيئة prodaction قبل توقف / إعادة تحميل الحاوية بسبب قيود موارد الاستضافة لكل حاوية.

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

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

ومن المثير للدهشة حقًا أنه يمكننا تنفيذ خدمة قد تتعامل مع كمية لا يمكن التنبؤ بها من السجلات وتستهلك باستمرار فقط بضع ميغابايت مع مساعدة كلمة رئيسية واحدة فقط - "العائد" *.

الوقت لمثال:

 class Program { static void Main(string[] args) { // 1. Load byline a set of records from a file or DB into memory. var users = LoadUsers(); // 2. For each column of the record change the value to someone other value. users = ModifyFirstName(users); // 3. Save the results of transformation into a file or DB. SaveUsers(users); } private static IEnumerable<User> LoadUsers() { foreach(var line in File.ReadLines("text.txt")) { var splitedLine = line.Split(';'); yield return new User() { FirstName = splitedLine[0], LastName = splitedLine[1] }; } } private static IEnumerable<User> ModifyFirstName(IEnumerable<User> users) { foreach (var user in users) { user.FirstName += "_1"; yield return user; } } private static void SaveUsers(IEnumerable<User> users) { foreach(var user in users) { File.AppendAllLines("results.txt", new string []{ user.FirstName + ';' + user.LastName }); } } private class User { public string FirstName { get; set; } public string LastName { get; set; } } } 

كما ترون في المثال أعلاه ، توجد ذاكرة مخصصة فقط لكائن واحد في وقت واحد: "غلة إرجاع مستخدم جديد ()" بدلاً من إنشاء مجموعة وتعبئتها بالكائنات. إنها النقطة الرئيسية للتحسين التي تسمح لنا بحساب أثر ذاكرة أكثر قابلية للتنبؤ بالخدمة. لأننا نحتاج فقط إلى معرفة حجم الحقلين ، في حالتنا الاسم الأول واسم العائلة. عندما يتم حفظ مستخدم تم تعديله في ملف (راجع File.AppendAllLines) ، يكون مثيل كائن المستخدم متاحًا لجمع البيانات المهملة. يتم إلغاء تخصيص الذاكرة التي يشغلها الكائن (أي التكرار التالي لبيان "foreach" في LoadUsers) ، لذلك يمكن إنشاء المثيل التالي لكائن المستخدم. بمعنى آخر ، تقريبًا ، يستبدل نفس مقدار الذاكرة بنفس مقدار الذاكرة في كل تكرار. هذا هو السبب في أننا لسنا بحاجة إلى ذاكرة أكبر من حجم سجل واحد في الملف.

نتائج منشئ ملفات التعريف الذاكرة بعد التحسين:

صورة

من منظور آخر ، إذا قمنا بإعادة تسمية بعض الطرق في التطبيق أعلاه قليلاً ، بحيث يمكن أن يلاحظ هذا الاستخدام بعض المنطق المجدي لوحدات التحكم في تطبيق MVC:

 private static void GetUsersAction() { // 1. Load byline a set of records from a file or DB into memory. var users = LoadUsers(); // 2. For each column of the record change the value to someone other value. var usersDTOs = MapToDTO(users); // 3. Save the results of transformation into a file or DB. OkResult(usersDTOs); } 

ملاحظة مهمة واحدة قبل إدراج الكود: معظم المكتبات المهمة مثل EntityFramework و ASP.net MVC و AutoMapper و Dapper و NHibernate و ADO.net وغيرها تستكشف / تستهلك مصادر IEnumerables. لذلك ، فهذا يعني في المثال أعلاه أنه يمكن استبدال LoadUsers بتنفيذ يستخدم EntityFramework ، على سبيل المثال. الذي يحمّل صف البيانات صفًا من جدول قاعدة البيانات ، بدلاً من الملف. قد يتم استبدال MapToDTO بـ Automapper ويمكن استبدال OkResult من خلال تطبيق "حقيقي" لـ IActionResult في بعض أطر عمل MVC أو قاعدة التنفيذ الخاصة بنا على ساحة الشبكة ، على سبيل المثال:

 private static void OkResult(IEnumerable<User> users) { // you can use a networksteam implementation using(StreamWriter sw = new StreamWriter("result.txt")) { foreach(var user in users) { sw.WriteLine(user.FirstName + ';' + user.LastName); } } } 

يوضح لنا مثال "mvc-like" هذا أننا لا نزال قادرين على توقع وحساب أثر الذاكرة أيضًا لتطبيق الويب. ولكن في هذه الحالة ، سوف يعتمد على عدد الطلبات أيضًا. على سبيل المثال ، قد تبدو المتطلبات غير الوظيفية بهذه الطريقة: "الحد الأقصى لمقدار الذاكرة عند 1000 طلب لا يزيد عن ذلك: 200 كيلو بايت لكل كائن مستخدم × 1000 طلب ~ 200 ميجابايت."

هذه الحسابات مفيدة للغاية لتحسين الأداء في حالة توسيع نطاق تطبيق الويب. على سبيل المثال ، تحتاج إلى توسيع نطاق تطبيق الويب الخاص بك على 100 حاوية / VMs. لذا ، في هذه الحالة ، لاتخاذ قرار بشأن مقدار الموارد التي يجب تخصيصها من مزود الاستضافة ، حتى تتمكن من ضبط الصيغة مثل: 200 كيلو بايت لكل كائن مستخدم × 1000 طلب × 100VMs ~ 20GB. علاوة على ذلك ، هذا هو الحد الأقصى لمقدار الذاكرة وهذا المقدار يقع تحت سيطرة ميزانية مشروعك.

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

Source: https://habr.com/ru/post/ar444358/


All Articles