سباق اللغات البرمجية لمناولة النصوص الضخمة.. من يكسب؟

ما هي اللغات البرمجية الأكثر قدرة على التعامل مع الملفات النصية الكبيرة؟ وماهي أكثرهم سرعة في ذلك؟

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

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

التفاصيل الفنية تركتها في آخر المقال للمهتمين. أو في منصة GitHub حيث وضعت الكود المصدري للغات المشاركة في السباق.

اللغات المستهدفة عددها 18 لغة وهي: Rust, Go, C, C++, Free Pascal, C#, F#, Java, Python, OCaml, Dart, D, Nim, V, Julia, Red, Crystal, Perl.

بعض الملاحظات السريعة قبل بدء السباق:

  • حتى يتم تسريع عمل بناء الكتلة النصية، قمت باستخدام وظيفة ال String Builder في كل لغة، بعض اللغات تستخدم نفس التقنية داخليا مثل Rust، لغة C لاتوجد بها هذه التقنية فتم بناء مجموعة إجراءات لمحاكاة هذه التقنية.
  • لم أقم بأية عمليات ضبط أو حيل لتسريع أو تحسين الأداء، واكتفيت باستخدام ما تقدمة اللغة بداهة.
  • لنفس السبب السابق، كان يمكن حفظ النص الضخم على دفعات chunks بدل أن يفشل البرنامج في حفظه دفعة واحدة وبدل ذلك تركت الأمر للقدرات الموجودة في كل لغة.
  • السباق لايعدّ اختبارا مهنيا دقيقا، لأن الاختبارات الحقيقية يتم بناؤها لفحص أداء عدة محاور في البرمجة وليس فقط بناء كتلة نصية (مجرّد فضول شخصي لمعرفة قدرة كل لغة في جانب محدد).
  • لست خبيرا في أي من اللغات المستخدمة.
  • سنتحدث ما أمكن عن كل لغة في سياق الحديث داخل المقال.
  • تم الاستعانة بالذكاء الصناعي لإعداد برنامج كل لغة.
  • زمن التنفيذ محسوب بالدقيقة والثانية وأجزاء من الثانية.

السباق:

الآن لنرى ما الذي تستطيعه كلّ لغة.

الجولة الأولى:

تستهدف الجولة الأولى بناء كتلة نصية بحجم 513 ميقا بايت، من خلال تكرارات عددها 50 مليون تكرار فكانت نتيجة سرعة الأداء كالتالي:

50,000,000 - 513 MB

Language Time
Rust 00:00:814
Crystal 00:00:823
Java 00:00:870
C# 00:01:45
F# 00:01:51
Nim 00:01:99
Perl 00:02:14
C++ 00:02:10
C 00:02:20
Go 00:03:70
D 00:04:13
Python 00:04:16
Free Pascal 00:04:52
Dart 00:06:10
V 00:06:20
Julia 00:07:89
OCaml 00:08:33
RED 00:16:93

الثلاثة الأكثر سرعة هم بالترتيب Rust ثم Crystal ثم جافا بسرعات متساوية تقريبا. كنت أتوقع C و C++ أن تكونا في المقدمة، بسبب شهرتهما بالسرعة بين اللغات و وأنهما عادة الأساس لمقارنة أداء اللغات الأخرى. كذلك لم أتوقّع أن تكون جافا بهذه السرعة مقارنة ب C#. نلاحظ أيظا أن F# أبطأ قليلا من C# برغم أنها تعملان في نفس البيئة .Net أحد أسباب ذلك أن F# يتم تحويلها أولا إلى C# قبل ترجمتها ل Byte code .

لغة Crystal جاءت الثانية بعد Rust لم أكن أتوقّع ذلك، كذلك الأمر بالنسبة للغة Perl التي تفوّقت على C و C++.

نتيجة لغة Go تبدو جيدة (أقل من أربع ثواني)، المفاجأة الكبيرة كانت لغة Python التي استطاعت أن تسبق لغات مثل Free Pascal.

لغة Red جاءت الأخيرة للأسف مسجلة 17 ثانية أي ضعف اللغة التي قبلها في الترتيب ، أقول لللأسف لأنها لغة أحبها وأحب فلسفتها وصيغتها النحوية وأصحابها يسوقون للهجة منها للتعامل مع تقنيات BlockChain.

الجولة الثانية

تستهدف بناء كتلة نصية بحجم 1 قيقا بايت، من خلال تكرارات عددها 100 مليون تكرار فكانت نتيجة الأداء كالتالي:

100,000,000 - 1.01 GB

Language Time Notes
Rust 00:01:625
Crystal 00:01:662
Java 00:01:770 Failed to save
C# 00:02:89 Failed to save
Nim 00:03:89
C++ 00:04:14
C 00:04:41
Perl 00:04:497
Go 00:07:51
D 00:08:34
Python 00:08:62
Free Pascal 00:09:08
V 00:13:30
Dart 00:13:68
Julia 00:15:47
OCaml 00:17:09
    F# Failed
    RED Failed

لنرى أولا من خرج من السباق. لغتان هما Red و F# . كما رأينا في الجولة السابقة لغة Red جاءت الأخيرة وبفارق كبير مع ما قبلها ، أما لغة F# فمن المحزن خروجها مبكرا، وهذا يدفعنا للتساؤل : هل ستقاوم أختها C# في الجولات القادمة؟

لغة Rust كانت في المقدمة تليها كريستال ثم Java بعدها لغة C# بضعف سرعة جافا ، نلاحظ أن جافا و C# فشلتا في حفظ النص في ملف. أي نجحتا في إعداد الكتلة النصية المطلوبة في الذاكرة و لم تتمكنا من حفظها في ملف نصّي.

لغة Crystal أداؤها ممتاز وهي من اللغات التي تهدف لتكون بديلا عن لغة C/C++ ، واستلهمت لغة Ruby لتكون لغة أنيقة وموجزة ومعبّرة.

لغة Nim مازالت تحتفظ بأسبقيتها على لغة C. في الواقع لغة Nim يقوم محوّلها بتحويلها إلى لغة C أولا ثم باختيار أحد تنفيذات C يتم ترجمتها لملف تنفيذي، لذلك لا نستغرب سرعة الأداء لديها. برنامج Python كان سريعا في هذه الجولة أيضا.

كانت لغة V بطيئة (13 ثانية) عكس الدعاية التي تحاط بها من قبل القائمين عليها لتكون بديلا للغة C، هذا الأداء المخيّب للآمال يطرح شكوكا حول امكانيات أدائها واستمراها في هذا السباق. أيضا لغة Dart قدمت أدءًا عاديا، هذه اللغة من شركة قوقل وهي اللغة الرسمية لإطار Flutter المنتشر بقوة للتطوير المتعدد المنصّات خاصة لتطبيقات الهواتف .

الجولة الثالثة:

تمت مضاعفة حجم الكتلة النصية المطلوب إنشاؤها ل 2 قيقا بزيادة عدد التكرارات إلى 200 مليون تكرار. وهذه النتائج:

200,000,000 - 2.13 GB

Language Time Notes
Rust 00:03:289
C++ 00:08:318 Failed to save
Nim 00:08:37 Failed to save
Perl 00:09:105
C 00:09:92
Python 00:19:27
D 00:22:28
Go 00:25:51
Julia 00:31:27
OCaml 00:35:42
Dart 00:40:70
    Java Failed
    C# Failed
    Crystal Failed
    Free Pascal Failed
    V Failed

خرجت جافا من السباق، وكما كان متوقعا بعد خروج F#؛ خرجت أختها لغة C# ، وخرجت معهم Free Pascal و Crystal و لغة V. لغات جافا و F# و C# و Crystal قدمت أداءًا متفوقا لكن ليس مع الأحجام الكبيرة من البيانات.

المتصدر لسباق السرعة هي Rust، ثم - وبفارق كبير - لفات Cو Nim و Perl بأداء متقارب ثم C++. إلا أن C++ و Nim الوحيدتان اللتان فشلتا في حفظ الكتلة النصية في ملف.

لازالت لغة Python متقدمة وتسبق لغات يفترض أنها سريعة مثل D و Go

آخر القائمة كانت لغة OCaml وهي اللغة الأم للغة F# (لغة F# هي تنفيذ للغة OCaml على بيئة .Net) قبلها كانت لغة Julia .

لغة Julia ظهرت 2012 وهي لغة تستهدف التحليلات الاحصائية والرقمية والمسائل العلمية والاحصائيات ولتكون خلفا للغة R يتم تشغيلها بمفسّر interpreter مثل لغة Python و Perl.

الجولة الرابعة:

في هذه الجولة الكتلة النصية يمكن أن نقول عنها فعلا انها ضخمة حيث تبلغ حوالي 6 قيقا بايت يتم صنعها ب 500 مليون تكرار:

500,000,000 - 5.48 GB

Language Time Notes
Rust 0:08:131
C++ 00:20:338 Failed to save
C 00:19:198 Failed to save
Nim 00:20:57 Failed to save
Perl 00:23:482
Python 00:42:80
D 01:05:4
Go 01:07:53
Julia 01:16:79
OCaml 01:30:925
Dart 03:36:484

في هذه الجولة لم يخرج أحد من السباق،Rust في رأس القائمة تليها بفارق كبير C++ ، لكن لغة C لم تتمكن من حفظ الملف النصي في هذه الجولة. لازالت Perl و Python تبهرانا بسرعتهما متقدمة على لغات يفترض أنها محسوبة على اللغات السريعة مثل Julia و D. لكن نكرر أن الاختبارات الحقيقية لأداء اللغات تستند على عدة محاور ولا يتم الحكم على أداء لغة ما من جانب واحد فط.

لغة Dart سجّلت 3.5 دقيقية فكانت بطيئة مقارنة بسرعة لغة Rust التي كانت 8 ثواني،، لكن بالمقابل لغة Dart أنجزت كامل المهمة بنجاح بحفظها للملف في الوقت الذي فشلت فيه لغات C و C++ وNim.

الجولة الخامسة:

تمت مضاعقة حجم لكتلة النصية لتصبح 11 قيقا بايت وبعدد تكرارات ألف مليون تكرار.

في هذه الجولة لم يخرج أحد من السباق،Rust في رأس القائمة تليها بفارق كبير C++ . لازالت Perl و Python تبهرانا بسرعتهما متقدمتان على لغات يفترض أنها محسوبة على اللغات السريعة مثل Julia و D. لكن نكرر أن الاختبارات الحقيقية لأداء اللغات تستند على عدة محاور ولا يتم الحكم على أداء لغة ما من جانب واحد فط.

لغة Dart سجّلت 3.5 دقيقية فكانت بطيئة مقارنة بسرعة لغة Rust التي كانت 8 ثواني،، لكن بالمقابل لغة Dart أنجزت كامل المهمة بنجاح بحفظها للملف في الوقت الذي فشلت فيه لغات C و C++ وNim.

الجولة الخامسة:

تمت مضاعقة حجم لكتلة النصية لتصبح 11 قيقا بايت وبعدد تكرارات ألف مليون تكرار.

1000,000,000 - 11.0 GB

Language Time Notes
Rust 00:27:184
C 00:41:41 Failed to save
C++ 00:51:93 Failed to save
Nim 01:15:164 Failed to save
Python 01:41:46
Perl 01:29:107
Julia 02:58:553
Go 05:24:528
     D Failed
     OCaml Failed
     Dart Failed

في هذه الجولة خرجت اللغات D وOCaml و Dart، ولا فرق تقريبا في ترتيب سرعة اللغات. D من اللغات الجميلة والداعمة لعدة مذاهب برمجية Paradigms ، أما لغةOCaml فهي من عائلة ML مثل Haskel و F# وهي أولى محاولات نقل اللغات الدالية Functional من الوسط الأكاديمي إلى الوسط الصناعي ، وأتبثت فعاليتها في التطبيقات العلمية والمالية.

الجولة السادسة:

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

في هذه الجولة حجم الكتلة النصية 17 قيقا بايت، أي أكثر من 18 مليار حرف، عبر مليار و500 مليون تكرار، وهذه النتائج:

1500,000,000 - 17.1 GB

Language Time Notes
Rust 01:58:878
C 02:14:134 Failed to save
C++ 02:26:846 Failed to save
Nim 02:29:30 Failed to save
Perl 03:46:818
Python 04:23:69 Failed to save
Julia 06:43:273
Go 13:25:161

لم يخرج أحد في هذه الجولة ولكن هنا تفشل Python في حفظ الملف مثل C و Nim رغم أنها نجحت في توليده وبسرعة تفوقت بها على Go و Julia. لغة Go متأخرة كثيرا فهي أبطا الجميع بمسافة كبيرة، فبينها وبين C ما يزيد عن 11 دقيقة ، وبينها وبين اللغة التي تسبقها Julia ستة دقائق.

لغة Perl بالنسبة لي هي مفاجأة هذا السباق، هي لغة قديمة ظهرت في 1987 بغرض معالجة النصوص في الملفات النصية وتحليلها واستخراج النتائج منها، وتطوّرت لتكون لغة متكاملة ، ولكن تراجعت شعبيتها بسبب غرابة تركيبها النحوي المختصر وأخذت مكانها لغة بايثون. ولأنها أصلا مصممة لمناولة النصوص وتحليلها، لذلك يمكن أن يكون هذا سبب تفوقها في هذا السباق.

أيضا نلاحظ أن الفارق الزمني بدأ يتقلّص بين Rust ولغات C و C++.

الجولة السابعة:

تضخّمت الكتلة النصية لتبلغ 24 قيقا بايت من خلال 2 بليون تكرار، وهذه نتيجة الاختبارات:

2000,000,000 - 23.1 GB

Language Time Notes
Rust 02:18:98
C 02:30:15 Failed to save
C++ 02:41:351 Failed to save
Nim 04:44:49 Failed to save
Perl 09:34:90
Julia 10:14:19
     Go Failed
     Python Failed

تحية كبرى للغة Julia و لغة Perl ، صامدتان مع الكبار دون أن تفشلا في حفظ الملف. في الوقت التي خرجت فيه كل من Go و Python. أيضا يتاكد تقلّص الفارق الزمني بين Rust و C.

الجولة الثامنة: (الأخيرة)

تم زبادة حجم الكتلة النصية إلى مايقرب من 30 قيقا بايت:

2500,000,000 - 29.2 GB

Language Time Notes
Rust 02:22:671
C++ 03:07:973 Failed to save
Nim 04:46:262 Failed to save
     C Failed
     Julia Failed
     Perl Failed

في هذه الجولة خرجت المبجّلة C وكذلك Julia و Perl، ولم يبق إلا Rust و C++ و Nim .

لغة Rust لازالت الأسرع وهي الوحيدة التي استطاعت حفظ الملف.

الجولة بعد الأخيرة:

تم زيادة عدد التكرارات إلى 3000 مليون مرة، و لم يفز أحد.

3000,000,000

Language Notes
     Rust Failed
     C++ Failed
     Nim Failed

نتيجة السباق :

  • اللغة الأسرع في جميع أحجام النصوص الصغيرة والضخمة هي لغة Rust
  • اللغة التي استطاعت حفظ أكبر حجم للنص هي لغة Rust
  • اللغات التي قاومت لنهاية السباق هي: Rust, Nim, C++
  • اللغات الأكثر تحملا للإجهاد في هذا السباق هي: C ، C++ ، Nim ، Rust ، Python ، Julia ، Go، Perl

ملاحظات:

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

يمكن مراجعة التفاصيل الفنية والملفات المصدرية والتنفيذية في منصة GitHub في الرابط التالي:

https://github.com/shagrouni/langs_string_build_test

أيضا يمكن متابعة النقاشات التي تمت حول هذا السباق في مجتمع لغة Rust في منصة Reddit:

https://www.reddit.com/r/Rust/comments/1fe3fe7/handling_large_string_in_different_languages