كيفية عدم استخدام Node.js Stream API

شخص ما مخطئ على الإنترنت مرة أخرى - في Node Weekly أمس كان هناك رابط إلى مشاركة يحاول المؤلف فيها قياس ومقارنة أداء Stream API في Node.js. يتسبب الحزن في كيفية عمل المؤلف مع الجداول وما هي الاستنتاجات التي يحاول استخلاصها على أساس هذا:


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

دعونا نحاول معرفة ما هو الخطأ في استنتاجات ورمز المؤلف.


من وجهة نظري ، المشكلة هي أن كاتب المقال لا يعرف كيفية استخدام Stream'ami وهذه مشكلة يجب على المرء التعامل معها في كثير من الأحيان. هذه الظاهرة ، في رأيي ، لها ثلاثة أسباب:


  1. القصة المعقدة لـ Node.js Stream API - الألم والمعاناة الموصوفة هنا
  2. ليست واجهة برمجة التطبيقات الأكثر بديهية إذا حاولت استخدامها بدون أي أغلفة
  3. وثائق غريبة جدا تقدم التدفقات كشيء معقد للغاية ومنخفض المستوى

معًا ، يؤدي هذا إلى حقيقة أن المطورين غالبًا لا يعرفون كيف ولا يريدون استخدام Stream API.


ما هو الخطأ في كود المؤلف ؟
للبدء ، دعنا نكرر المهمة هنا (يمكن العثور على الأصل باللغة الإنجليزية ورابط للملف في المشاركة):
هناك ملف 2.5 غيغابايت مع خطوط النموذج:


C00084871|N|M3|P|201703099050762757|15|IND|COLLINS, DARREN ROBERT|SOUTHLAKE|TX|760928782|CELANESE|VPCHOP&TECH|02282017|153||PR2552193345215|1151824||P/R DEDUCTION ($76.92 BI-WEEKLY)|4030920171380058715 

تحتاج إلى تحليله ومعرفة المعلومات التالية:


  • عدد الأسطر في الملف
  • الأسماء على الخطين 432 و 43243 (هنا تبرز الحقيقة مسألة كيفية الحساب ، من 0 أو 1؟)
  • الاسم الأكثر شيوعًا وعدد مرات حدوثه
  • عدد الأقساط لكل شهر

ما هي المشكلة؟ - يقول المؤلف بصراحة أنه يحمّل الملف بالكامل في الذاكرة ، وبسبب هذا ، "تعليق" العقدة ويعطينا المؤلف حقيقة مثيرة للاهتمام.


حقيقة ممتعة: يمكن لـ Node.js استيعاب ذاكرة تصل إلى 1.67 جيجابايت فقط في المرة الواحدة

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


 const { Writable } = require('stream') const fs = require('fs') const split = require('split') let counter = 0 const linecounter = new Writable({ write(chunk, encoding, callback) { counter = counter + 1 callback() }, writev(chunks, callback) { counter = counter + chunks.length callback() } }) fs.createReadStream('itcont.txt') .pipe(split()) .pipe(linecounter) linecounter.on('finish', function() { console.log(counter) }) 

ملحوظة : الرمز مكتوب عمداً في أبسط صورة ممكنة. المتغيرات العالمية سيئة!


ما يجب الانتباه إليه:


  • Split - npm حزمة تتلقى دفقًا من الخطوط عند "الإدخال" - تُرجع دفقًا من مجموعات الخطوط إلى "الإخراج" مع فاصل أسطر منفصل. على الأرجح جعله تنفيذ تيار التحول. ننقل إليه ملف ReadStream الخاص بنا مع ملف ، ثم نوجه نفسه إلى ...
  • linecounter - تنفيذ WritableStream. نطبق فيه طريقتين: لمعالجة قطعة واحدة (قطعة) وعدة. "الخط" في هذه الحالة هو سطر الكود. عكس - أضف الرقم المطلوب إلى العداد. من المهم أن نفهم أنه في هذه الحالة لن نقوم بتحميل الملف بأكمله في الذاكرة ، وسوف تقسم واجهة برمجة التطبيقات كل شيء بالنسبة لنا إلى "أجزاء" أكثر ملاءمة للمعالجة
  • "النهاية" - الأحداث "التي تحدث" عندما تنتهي البيانات التي تصل إلى ReadableStream. عندما يحدث هذا نتعهد بيانات العداد

حسنًا ، دعنا نختبر إبداعنا على ملف كبير:


 > node linecounter.js 13903993 

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


أخبر:


  • هل أنت مهتم بقراءة كيفية حل المشكلة تمامًا وكيفية إدخال الشفرة الناتجة في نموذج مناسب للصيانة؟
  • هل تستخدم Stream API وما الصعوبات التي واجهتها؟

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


All Articles