
منذ بداية عام 2017 ، يعمل فريقنا الصغير على تطوير
مكتبة RESTinio OpenSource لتضمين خادم HTTP في تطبيقات C ++. لدهشتنا العظيمة ، من وقت لآخر نتلقى أسئلة من الفئة "ولماذا قد تكون هناك حاجة لخادم C ++ HTTP مضمن؟" للأسف ، الأسئلة البسيطة هي الأصعب في الإجابة. في بعض الأحيان يكون أفضل إجابة هو نموذج التعليمات البرمجية.
بدأنا قبل شهرين
مشروعًا تجريبيًا صغيرًا
، هو الروبيان ، والذي يوضح بوضوح سيناريو نموذجي ، يتم بموجبه "شحذ" مكتبتنا. المشروع التجريبي هو خدمة ويب بسيطة تتلقى طلبات لتغيير حجم الصور المخزنة على الخادم وتعرض صورة بالحجم الذي يحتاجه المستخدم.
هذا المشروع التجريبي جيد في أنه ، أولاً ، يتطلب التكامل مع رمز مكتوب ويعمل بشكل صحيح منذ وقت طويل في C أو C ++ (في هذه الحالة ، ImageMagick). لذلك ، يجب أن يكون من الواضح لماذا من المنطقي أن يتم تضمين خادم HTTP في تطبيق C ++.
وثانيًا ، في هذه الحالة ، يلزم معالجة الطلب غير المتزامن بحيث لا يتم حظر خادم HTTP أثناء تغيير حجم الصورة (ويمكن أن يستغرق ذلك مئات المللي ثانية أو حتى الثواني). وقد بدأنا في تطوير RESTinio على وجه التحديد لأنه لم نتمكن من العثور على خادم مضمن C ++ عاقل يركز بشكل خاص على معالجة الطلبات غير المتزامنة.
قمنا ببناء العمل على الجمبري بشكل متكرر: أولاً ، تم إنشاء
ووصف أبسط نسخة ، والتي قامت فقط بتحجيم الصور. ثم قمنا بإصلاح عدد من أوجه القصور في الإصدار الأول
ووصفنا ذلك في المقالة الثانية . أخيرًا ، توصلنا إلى توسيع وظائف الروبيان مرة أخرى: تمت إضافة تحويل الصور من تنسيق إلى آخر. حول كيفية القيام بذلك وسيتم مناقشته في هذه المقالة.
دعم تنسيق الهدف
لذا ، في الإصدار التالي من Shrimp ، أضفنا القدرة على إعطاء صورة بمقاس بتنسيق مختلف. لذا ، إذا قمت بإصدار طلب الجمبري من النموذج:
curl "http://localhost:8080/my_picture.jpg?op=resize&max=1920"
ثم سيعرض الروبيان الصورة بنفس تنسيق JPG للصورة الأصلية.
ولكن إذا قمت بإضافة معلمة تنسيق الهدف إلى عنوان URL ، فإن برنامج Shrimp يحول الصورة إلى تنسيق الهدف المحدد. على سبيل المثال:
curl "http://localhost:8080/my_picture.jpg?op=resize&max=1920&target-format=webp"
في هذه الحالة ، سيعرض Shrimp الصورة بتنسيق صفحة الويب.
يدعم الروبيان المحدث خمسة تنسيقات صور: jpg و png و gif و webp و heic (المعروف أيضًا باسم HEIF). يمكنك تجربة تنسيقات مختلفة
على صفحة ويب خاصة :

(لا توجد طريقة في هذه الصفحة لتحديد التنسيق الثابت ، لأن متصفحات سطح المكتب العادية لا تدعم هذا التنسيق بشكل افتراضي).
من أجل دعم تنسيق الهدف في الجمبري ، كان مطلوبًا تعديل رمز الجمبري قليلاً (والذي فوجئنا بأنفسنا ، لأنه كانت هناك تغييرات قليلة حقًا). ولكن من ناحية أخرى ، كان علي أن ألعب مع جمعية ImageMagick ، التي فوجئنا بها أكثر ، مثل في وقت سابق ، كان علينا التعامل مع هذا المطبخ ، بمصادفة محظوظة. ولكن دعونا نتحدث عن كل شيء بالترتيب.
يجب أن يفهم ImageMagick تنسيقات مختلفة
يستخدم ImageMagick مكتبات خارجية لترميز / فك تشفير الصور: libjpeg ، libpng ، libgif ، إلخ. يجب تثبيت هذه المكتبات على النظام قبل تكوين ImageMagick وبناؤه.
يجب أن يحدث نفس الشيء من أجل أن يدعم ImageMagick تنسيقات web و heic: أولاً تحتاج إلى إنشاء وتثبيت libwebp و libheif ، ثم تكوين ImageMagick وتثبيته. وإذا كان كل شيء بسيطًا مع libwebp ، فعندئذ كان يجب علي الرقص مع الدف. على الرغم من أنه بعد مرور بعض الوقت ، بعد أن اجتمع كل شيء وعمل في النهاية ، لم يكن واضحًا بالفعل: لماذا كان عليك اللجوء إلى الدف ، يبدو كل شيء تافهًا؟ ؛)
بشكل عام ، إذا كان شخص ما يريد تكوين صداقات مع heic و ImageMagick ، فسيتعين عليك تثبيت:
في هذا الترتيب (قد تضطر إلى تثبيت
nasm بحيث يعمل x265 بأقصى سرعة). بعد ذلك ، عند إصدار الأمر. /
configure ، سيتمكن ImageMagick من العثور على كل ما يحتاجه لدعم ملفات .heic.
دعم تنسيق الهدف في سلسلة الاستعلام للطلبات الواردة
بعد تكوين صداقات مع ImageMagick باستخدام تنسيقات الويب والويب ، حان الوقت لتعديل كود الجمبري. بادئ ذي بدء ، نحتاج إلى معرفة كيفية التعرف على وسيطة تنسيق الهدف في طلبات HTTP الواردة.
من وجهة نظر RESTinio ، هذه ليست مشكلة على الإطلاق. حسنًا ، ظهرت حجة أخرى في سلسلة الاستعلام ، فماذا؟ ولكن من وجهة نظر الجمبري ، اتضح أن الوضع أكثر تعقيدًا إلى حد ما ، لذلك أصبح رمز الوظيفة المسؤولة عن تحليل طلب HTTP أكثر تعقيدًا.
والحقيقة هي أنه قبل أن يكون من الضروري التمييز بين حالتين فقط:
- جاء طلب شكل "/filename.ext" بدون أي معلمات أخرى. لذلك تحتاج فقط إلى إعطاء الملف "filename.ext" كما هو ؛
- جاء الطلب بصيغة "/filename.ext؟op=resize & ...". في هذه الحالة ، تحتاج إلى تغيير حجم الصورة من ملف "filename.ext".
ولكن بعد إضافة تنسيق الهدف ، نحتاج إلى التمييز بين أربع حالات:
- جاء طلب شكل "/filename.ext" بدون أي معلمات أخرى. لذلك تحتاج فقط إلى إعطاء الملف "filename.ext" كما هو ، بدون تغيير الحجم وبدون تحويل إلى تنسيق آخر ؛
- جاء طلب النموذج "/filename.ext؟target-format=fmt" بدون أي معلمات أخرى. يعني أخذ صورة من ملف "filename.ext" وتحويلها إلى تنسيق "fmt" مع الحفاظ على الأحجام الأصلية ؛
- جاء طلب من النموذج "/filename.ext؟op=resize & ..." ولكن بدون تنسيق الهدف. في هذه الحالة ، تحتاج إلى تغيير حجم الصورة من ملف "filename.ext" وإعطائها في التنسيق الأصلي ؛
- جاء طلب من النموذج "/filename.ext؟op=resize&...&target-format=fmt". في هذه الحالة ، تحتاج إلى إجراء القياس ، ثم تحويل النتيجة إلى تنسيق "fmt".
ونتيجة لذلك ، اتخذت وظيفة تحديد معلمات الاستعلام
الشكل التالي :
void add_transform_op_handler( const app_params_t & app_params, http_req_router_t & router, so_5::mbox_t req_handler_mbox ) { router.http_get( R"(/:path(.*)\.:ext(.{3,4}))", restinio::path2regex::options_t{}.strict( true ), [req_handler_mbox, &app_params]( auto req, auto params ) { if( has_illegal_path_components( req->header().path() ) ) { // . return do_400_response( std::move( req ) ); } // . const auto qp = restinio::parse_query( req->header().query() ); const auto target_format = qp.get_param( "target-format"sv ); // // . target-format, // . target-format // , , // . const auto image_format = try_detect_target_image_format( params[ "ext" ], target_format ); if( !image_format ) { // . . return do_400_response( std::move( req ) ); } if( !qp.size() ) { // , . return serve_as_regular_file( app_params.m_storage.m_root_dir, std::move( req ), *image_format ); } const auto operation = qp.get_param( "op"sv ); if( operation && "resize"sv != *operation ) { // , resize. return do_400_response( std::move( req ) ); } if( !operation && !target_format ) { // op=resize, // target-format=something. return do_400_response( std::move( req ) ); } handle_resize_op_request( req_handler_mbox, *image_format, qp, std::move( req ) ); return restinio::request_accepted(); } ); }
في الإصدار السابق من Shrimp ، حيث لم تكن بحاجة إلى ترميز الصورة ،
بدا العمل مع معلمات الطلب
أسهل قليلاً .
طلب قائمة انتظار وذاكرة تخزين مؤقت للصور مصممة لتنسيق الهدف
كانت النقطة التالية في تنفيذ دعم تنسيق الهدف هي العمل في قائمة انتظار الطلبات وذاكرة التخزين المؤقت للصور الجاهزة في وكيل a_transform_manager. تحدثنا عن هذه الأشياء بمزيد من التفصيل
في المقالة السابقة ، ولكن دعنا نذكرك قليلاً بما كان عليه.
عند وصول طلب تحويل صورة ، فقد يتبين أن الصورة النهائية بمثل هذه المعلمات موجودة بالفعل في ذاكرة التخزين المؤقت. في هذه الحالة ، لا تحتاج إلى القيام بأي شيء ، فقط أرسل الصورة من ذاكرة التخزين المؤقت ردًا. إذا كانت الصورة بحاجة إلى تحويل ، فقد يتبين أنه لا يوجد عمال أحرار في الوقت الحالي وعليك الانتظار حتى تظهر. للقيام بذلك ، يجب وضع قائمة انتظار المعلومات المطلوبة. ولكن في نفس الوقت ، من الضروري التحقق من تفرد الطلبات - إذا كان لدينا ثلاثة طلبات متطابقة تنتظر المعالجة (أي ، نحتاج إلى تحويل نفس الصورة بنفس الطريقة) ، فيجب علينا معالجة الصورة مرة واحدة فقط وإعطاء نتيجة المعالجة لهذه الطلبات الثلاثة. على سبيل المثال في قائمة انتظار الانتظار ، يجب تجميع الطلبات المتطابقة.
في وقت سابق في Shrimp ، استخدمنا مفتاحًا مركبًا بسيطًا للبحث في ذاكرة التخزين المؤقت للصور وقائمة انتظار الانتظار:
مزيج من اسم الملف الأصلي + خيارات تغيير حجم الصورة . الآن ، يجب مراعاة عاملين جديدين:
- أولاً ، تنسيق الصورة الهدف (على سبيل المثال ، يمكن أن تكون الصورة الأصلية بتنسيق jpg ، ويمكن أن تكون الصورة الناتجة بتنسيق png) ؛
- ثانيًا ، حقيقة أن تحجيم الصورة قد لا يكون ضروريًا. يحدث هذا في الحالة التي يطلب فيها العميل فقط تحويل الصورة من تنسيق إلى آخر ، ولكن مع الحفاظ على الحجم الأصلي للصورة.
يجب أن أقول أننا ذهبنا على الطريق الأبسط ، دون محاولة تحسين أي شيء بطريقة أو بأخرى. على سبيل المثال ، يمكن للمرء أن يحاول إنشاء مخبأين مؤقتين: يقوم أحدهما بتخزين الصور بالتنسيق الأصلي ، ولكن يتم تحجيمها إلى الحجم المطلوب ، وفي الثانية ، يتم تحويل الصور المقاسة إلى التنسيق الهدف.
لماذا ستكون هناك حاجة إلى مثل هذا التخزين المؤقت المزدوج؟ والحقيقة هي أنه عند تحويل الصور ، فإن أغلى عمليتين في الوقت المناسب هما تغيير حجم الصورة وتسلسلها إلى التنسيق الهدف. لذلك ، إذا تلقينا طلبًا لتغيير حجم الصورة example.jpg إلى حجم 1920 وعرضه إلى تنسيق ويب ، فيمكننا تخزين صورتين في ذاكرتنا: example_1920px_width.jpg و example_1920px_width.webp. سنقدم صورة مثال_1920px_width.webp عندما تلقينا طلبًا ثانيًا. ولكن يمكن استخدام الصورة example_1920px_width.jpg عند تلقي طلبات لتغيير حجم example.jpg إلى حجم 1920 وعرضه وتحويله إلى تنسيق ثابت. يمكننا تخطي عملية تغيير الحجم والقيام بتحويل التنسيق فقط (على سبيل المثال ، سيتم تحويل الصورة النهائية example_1920px_width.jpg إلى تنسيق heic).
فرصة أخرى محتملة: عندما يأتي طلب لتحويل صورة إلى تنسيق آخر دون تغيير الحجم ، يمكنك تحديد الحجم الفعلي للصورة واستخدام هذا الحجم داخل المفتاح المركب. على سبيل المثال ، اسمحوا example.jpg بحجم 3000x2000 بكسل. إذا تلقينا بعد ذلك طلبًا لتغيير حجم example.jpg إلى ارتفاع 2000 بكسل ، فيمكننا على الفور تحديد أن لدينا بالفعل صورة بهذا الحجم.
نظريا ، كل هذه الاعتبارات تستحق الاهتمام. ولكن من وجهة نظر عملية ، ليس من الواضح مدى ارتفاع احتمال مثل هذا التطور للأحداث. على سبيل المثال كم مرة نتلقى طلبًا لتغيير حجم example.jpg إلى 1920 بكسل مع التحويل إلى صفحة الويب ، ثم طلبًا لتغيير الحجم نفسه للصورة نفسها ، ولكن مع التحويل إلى png؟ من الصعب قول عدم وجود إحصائيات حقيقية. لذلك ، قررنا عدم تعقيد حياتنا في مشروعنا التجريبي ، ولكننا نسير أولاً على أبسط مسار. مع توقع أنه إذا احتاج شخص ما إلى مخططات تخزين مؤقت أكثر تقدمًا ، فيمكن إضافتها لاحقًا ، بدءًا من سيناريوهات حقيقية وليست وهمية لاستخدام Shrimp.
ونتيجة لذلك ، في النسخة المحدثة من Shrimp ، قمنا بتوسيع المفتاح قليلاً ، مضيفًا إليه أيضًا معلمة مثل التنسيق الهدف:
class resize_request_key_t { std::string m_path; image_format_t m_format; resize_params_t m_params; public: resize_request_key_t( std::string path, image_format_t format, resize_params_t params ) : m_path{ std::move(path) } , m_format{ format } , m_params{ params } {} [[nodiscard]] bool operator<(const resize_request_key_t & o ) const noexcept { return std::tie( m_path, m_format, m_params ) < std::tie( o.m_path, o.m_format, o.m_params ); } [[nodiscard]] const std::string & path() const noexcept { return m_path; } [[nodiscard]] image_format_t format() const noexcept { return m_format; } [[nodiscard]] resize_params_t params() const noexcept { return m_params; } };
على سبيل المثال يختلف طلب تغيير حجم example.jpg حتى 1920 بكسل مع التحويل إلى png عن تغيير الحجم نفسه ، ولكن مع التحويل إلى webp أو heic.
لكن التركيز الرئيسي هو الاختباء
في التنفيذ الجديد لفئة resize_params_t ، التي تحدد الأحجام الجديدة للصورة التي تم تغيير حجمها.
في السابق ، كانت هذه الفئة تدعم ثلاثة خيارات: تم تعيين العرض فقط ، أو تم تعيين الارتفاع فقط ، أو تم تعيين الجانب الطويل (يتم تحديد الارتفاع أو العرض حسب حجم الصورة الحالي). وبناءً على ذلك ، فإن
طريقة resize_params_t :: value () تُرجع دائمًا بعض القيمة الحقيقية (ما هي القيمة التي
تحددها طريقة resize_params_t :: mode () ).
ولكن في الجمبري الجديد ، تمت إضافة وضع آخر - keep_original ، مما يعني أنه لم يتم تنفيذ القياس ويتم عرض الصورة بحجمها الأصلي. لدعم هذا الوضع ، كان على resize_params_t إجراء بعض التغييرات. أولاً ، تحدد طريقة
resize_params_t :: make () الآن ما إذا كان الوضع keep_original مستخدمًا (يُعتقد أن هذا الوضع يُستخدم إذا لم يتم تحديد أي من معلمات العرض والارتفاع والحد الأقصى في سلسلة الاستعلام للطلب الوارد). سمح لنا هذا بعدم إعادة كتابة
دالة handle_resize_op_request () ، التي تدفع طلب تغيير حجم الصورة المراد تنفيذها.
ثانيًا ، يمكن الآن استدعاء أسلوب
resize_params_t :: value () ليس دائمًا ، ولكن فقط عندما يختلف وضع القياس عن keep_original.
ولكن الشيء الأكثر أهمية هو أن
resize_params_t :: عامل <() استمر في العمل على النحو المنشود.
بفضل كل هذه التغييرات في a_transform_manager ، ظل كل من ذاكرة التخزين المؤقت للصور التي تم قياسها وقائمة انتظار الطلبات كما هي. ولكن الآن ، يتم تخزين المعلومات حول الاستعلامات المختلفة في هياكل البيانات هذه. لذا ، فإن المفتاح {"example.jpg" ، "jpg" ، keep_original} سيختلف عن المفتاح {"example.jpg" ، "png" ، keep_original} ، وعن المفتاح {"example.jpg" ، "jpg" ، العرض = 1920 بكسل}.
اتضح أنه بعد أن أفسد قليلاً مع تعريف هياكل البيانات البسيطة مثل resize_params_t و resize_params_key_t ، فقد تجنبنا تغيير الهياكل الأكثر تعقيدًا مثل ذاكرة التخزين المؤقت للصور الناتجة وقائمة انتظار الطلبات.
دعم تنسيق الهدف في a_transformer
حسنًا ، الخطوة الأخيرة في دعم تنسيق الهدف هي توسيع منطق عامل التحويل a_transformer بحيث يتم تحويل الصورة ، التي ربما تم تحجيمها بالفعل ، إلى التنسيق الهدف.
اتضح أنه أسهل طريقة للقيام بذلك ، كل ما كان مطلوبًا هو توسيع كود طريقة
a_transform_t :: handle_resize_request () :
[[nodiscard]] a_transform_manager_t::resize_result_t::result_t a_transformer_t::handle_resize_request( const transform::resize_request_key_t & key ) { try { m_logger->trace( "transformation started; request_key={}", key ); auto image = load_image( key.path() ); const auto resize_duration = measure_duration( [&]{ // // keep_original. if( transform::resize_params_t::mode_t::keep_original != key.params().mode() ) { transform::resize( key.params(), total_pixel_count, image ); } } ); m_logger->debug( "resize finished; request_key={}, time={}ms", key, std::chrono::duration_cast<std::chrono::milliseconds>( resize_duration).count() ); image.magick( magick_from_image_format( key.format() ) ); datasizable_blob_shared_ptr_t blob; const auto serialize_duration = measure_duration( [&] { blob = make_blob( image ); } ); m_logger->debug( "serialization finished; request_key={}, time={}ms", key, std::chrono::duration_cast<std::chrono::milliseconds>( serialize_duration).count() ); return a_transform_manager_t::successful_resize_t{ std::move(blob), std::chrono::duration_cast<std::chrono::microseconds>( resize_duration), std::chrono::duration_cast<std::chrono::microseconds>( serialize_duration) }; } catch( const std::exception & x ) { return a_transform_manager_t::failed_resize_t{ x.what() }; } }
بالمقارنة
مع الإصدار السابق ، هناك نوعان من الإضافات الأساسية.
أولاً ، استدعاء الأسلوب image.magick () السحري حقًا بعد تغيير الحجم. تخبر هذه الطريقة ImageMagick عن تنسيق الصورة الناتج. في الوقت نفسه ، لا يتغير تمثيل الصورة في الذاكرة - يستمر ImageMagick في تخزينها كما يناسبها. ولكن بعد ذلك ستؤخذ القيمة التي حددتها طريقة magick () في الاعتبار أثناء الاستدعاء التالي لـ Image :: write ().
ثانيًا ، يسجل الإصدار المحدث الوقت المستغرق لإجراء تسلسل للصورة إلى التنسيق المحدد. يعمل الإصدار الجديد من Shrimp الآن على إصلاح الوقت المنقضي في التحجيم والوقت المستغرق في التحويل إلى التنسيق الهدف بشكل منفصل.
لم يخضع باقي الوكيل a_transformer_t لأية تغييرات.
موازنة ImageMagick
بشكل افتراضي ، تم إنشاء ImageMagic بدعم OpenMP. على سبيل المثال من الممكن موازنة العمليات على الصور التي يقوم بها ImageMagick. يمكنك التحكم في عدد مهام سير العمل التي تستخدمها ImageMagick في هذه الحالة باستخدام متغير البيئة MAGICK_THREAD_LIMIT.
على سبيل المثال ، على جهاز الاختبار الخاص بي بالقيمة MAGICK_THREAD_LIMIT = 1 (أي بدون موازاة حقيقية) ، أحصل على النتائج التالية:
curl "http://localhost:8080/DSC08084.jpg?op=resize&max=2400" -v > /dev/null > GET /DSC08084.jpg?op=resize&max=2400 HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Connection: keep-alive < Content-Length: 2043917 < Server: Shrimp draft server < Date: Wed, 15 Aug 2018 11:51:24 GMT < Last-Modified: Wed, 15 Aug 2018 11:51:24 GMT < Access-Control-Allow-Origin: * < Access-Control-Expose-Headers: Shrimp-Processing-Time, Shrimp-Resize-Time, Shrimp-Encoding-Time, Shrimp-Image-Src < Content-Type: image/jpeg < Shrimp-Image-Src: transform < Shrimp-Processing-Time: 1323 < Shrimp-Resize-Time: 1086.72 < Shrimp-Encoding-Time: 236.276
يشار إلى الوقت المستغرق في تغيير الحجم في رأس وقت الروبيان. في هذه الحالة ، تبلغ 1086.72 مللي ثانية.
ولكن إذا قمت بتعيين MAGICK_THREAD_LIMIT = 3 على نفس الجهاز وقمت بتشغيل الروبيان ، فإننا نحصل على قيم مختلفة:
curl "http://localhost:8080/DSC08084.jpg?op=resize&max=2400" -v > /dev/null > GET /DSC08084.jpg?op=resize&max=2400 HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Connection: keep-alive < Content-Length: 2043917 < Server: Shrimp draft server < Date: Wed, 15 Aug 2018 11:53:49 GMT < Last-Modified: Wed, 15 Aug 2018 11:53:49 GMT < Access-Control-Allow-Origin: * < Access-Control-Expose-Headers: Shrimp-Processing-Time, Shrimp-Resize-Time, Shrimp-Encoding-Time, Shrimp-Image-Src < Content-Type: image/jpeg < Shrimp-Image-Src: transform < Shrimp-Processing-Time: 779.901 < Shrimp-Resize-Time: 558.246 < Shrimp-Encoding-Time: 221.655
على سبيل المثال تم تقليل وقت تغيير الحجم إلى 558.25 مللي ثانية.
وفقًا لذلك ، نظرًا لأن ImageMagick يوفر القدرة على موازاة الحسابات ، يمكنك استخدام هذه الفرصة. ولكن في الوقت نفسه ، من المرغوب فيه أن تكون قادرًا على التحكم في عدد خيوط العمل التي يأخذها الروبيان لنفسه. في الإصدارات السابقة من Shrimp ، لم يكن من الممكن التأثير على عدد سير العمل الذي أنشأه Shrimp. ويمكن القيام بذلك في النسخة المحدثة من الجمبري. أو من خلال متغيرات البيئة ، على سبيل المثال:
SHRIMP_IO_THREADS=1 \ SHRIMP_WORKER_THREADS=3 \ MAGICK_THREAD_LIMIT=4 \ shrimp.app -p 8080 -i ...
أو من خلال وسيطات سطر الأوامر ، على سبيل المثال:
MAGICK_THREAD_LIMIT=4 \ shrimp.app -p 8080 -i ... --io-threads 1 --worker-threads 4
القيم المحددة من خلال سطر الأوامر لها أولوية أعلى.
يجب التأكيد على أن MAGICK_THREAD_LIMIT يؤثر فقط على تلك العمليات التي تقوم ImageMagick بتنفيذها بنفسها. على سبيل المثال ، يتم تغيير الحجم بواسطة ImageMagick. لكن التحويل من تنسيق إلى مفوضين آخرين من ImageMagick إلى مكتبات خارجية. وكيف تتوازى العمليات في هذه المكتبات الخارجية هي مسألة منفصلة لم نفهمها.
الخلاصة
ربما ، في هذا الإصدار من الروبيان ، جلبنا مشروعنا التجريبي إلى حالة مقبولة. يمكن لأولئك الذين يرغبون في الرؤية والتجربة العثور على النصوص المصدر للروبيان على
BitBucket أو
GitHub . يمكنك أيضًا العثور على Dockerfile هناك لبناء الروبيان لتجاربك.
بشكل عام ، حققنا أهدافنا التي وضعناها لأنفسنا من خلال بدء هذا المشروع التجريبي. ظهر عدد من الأفكار لمزيد من التطوير لكل من RESTinio و SObjectizer ، وقد وجد بعضها بالفعل تجسيدًا لها. لذلك ، يعتمد ما إذا كان الجمبري سيطور في مكان آخر بشكل كامل على الأسئلة والرغبات. إذا كان هناك ، يمكن أن يتوسع الروبيان. إذا لم يكن الأمر كذلك ، فسيبقى Shrimp مشروعًا تجريبيًا وساحة تدريب للتجربة مع الإصدارات الجديدة من RESTinio و SObjectizer.
في الختام ، أود أن أعرب عن شكر خاص لـ
aensidhe على مساعدتهم ونصيحتهم ، والتي بدونها
ستكون رقصاتنا مع الدف أطول وحزينة.