Rust: [استقرار] غير متزامن / ينتظر MVP

تم إنشاؤها على ٢٦ يونيو ٢٠١٩  ·  58تعليقات  ·  مصدر: rust-lang/rust

هدف الاستقرار: 1.38.0 (خفض تجريبي 2019-08-15)

ملخص تنفيذي

هذا اقتراح لتحقيق الاستقرار في الحد الأدنى من ميزة غير متزامن / انتظار قابلة للتطبيق ، والتي تشمل:

  • التعليقات التوضيحية async على الوظائف والكتل ، مما تسبب في تأخيرها في التقييم وبدلاً من ذلك التقييم للمستقبل.
  • عامل تشغيل await ، صالح فقط ضمن سياق async ، والذي يأخذ المستقبل كوسيطة ويتسبب في المستقبل الخارجي الذي يمكن التحكم فيه حتى يكتمل المستقبل المنتظر.

المناقشات السابقة ذات الصلة

طلبات التعليقات:

مشاكل التتبع:

استقرار:

تم التوصل إلى قرارات رئيسية

  • يُبنى المستقبل الذي يقيمه التعبير غير المتزامن من حالته الأولية ، ولا يشغل أيًا من كود الجسم قبل الخضوع.
  • يستخدم بناء الجملة للوظائف غير المتزامنة نوع الإرجاع "الداخلي" (النوع الذي يتطابق مع تعبير return الداخلي) بدلاً من نوع الإرجاع "الخارجي" (النوع المستقبلي الذي يتم تقييم استدعاء الدالة إليه)
  • صيغة عامل التشغيل المنتظر هي "بنية نقطة postfix" expression.await ، على عكس الصيغة الأكثر شيوعًا await expression أو صيغة بديلة أخرى.

أعمال التنفيذ عرقلة الاستقرار

  • يجب أن تكون [x] fns غير المتزامن قادرة على قبول فترات حياة متعددة # 56238
  • يجب ألا يزيد حجم مولدات [x] أضعافا مضاعفة # 52924
  • [] الحد الأدنى من الوثائق القابلة للتطبيق لميزة غير متزامن / انتظار
  • [] اختبارات المترجم الكافية للسلوك

العمل المستقبلي

  • غير متزامن / انتظار في السياقات غير القياسية: يعتمد async و await حاليًا على TLS للعمل. هذه مشكلة تنفيذ وليست جزءًا من التصميم ، وعلى الرغم من أنها لا تمنع التثبيت ، إلا أنه من المفترض حلها في النهاية.
  • الدالات غير المتزامنة ذات الرتبة الأعلى: async كمعدِّل لقواعد الإغلاق الحرفية غير مستقرة هنا. هناك حاجة إلى مزيد من أعمال التصميم فيما يتعلق بالالتقاط والتجريد على عمليات الإغلاق غير المتزامن مع العمر.
  • طرق السمات غير المتزامنة: تتضمن أعمال تصميم وتنفيذ مهمة ، ولكنها ميزة مرغوبة للغاية.
  • معالجة الدفق: الزوج إلى سمة المستقبل في مكتبة العقود الآجلة هو سمة الدفق ، مكرر غير متزامن. يعد دمج الدعم لمعالجة التدفقات في std واللغة ميزة مرغوبة على المدى الطويل.
  • تحسين تمثيلات المولد: يمكن القيام بالمزيد من العمل لتحسين تمثيل المولدات لجعلها ذات حجم مثالي. لقد تأكدنا من أن هذه مسألة تحسين بشكل صارم وليست ذات أهمية جوهرية.

خلفية

يعتبر التعامل مع الإدخال / الإخراج غير المعوق مهمًا جدًا لتطوير خدمات شبكة عالية الأداء ، وهي حالة استخدام مستهدفة لـ Rust مع اهتمام كبير من مستخدمي الإنتاج. لهذا السبب ، لطالما كان الحل لجعل كتابة الخدمات باستخدام الإدخال / الإخراج غير المحظور مريحًا وعمليًا هدفًا لشركة Rust. ميزة عدم التزامن / الانتظار هي تتويج لهذا الجهد.

قبل الإصدار 1.0 ، كان لدى Rust نظام greenthreading ، حيث قدم Rust بديلاً بدائيًا للترابط على مستوى اللغة مبنيًا على IO غير المحجوب. ومع ذلك ، فقد تسبب هذا النظام في العديد من المشكلات: أهمها إدخال وقت تشغيل اللغة الذي أثر على أداء البرامج التي لم تستخدمه ، وإضافة إلى حمل FFI بشكل كبير ، ووجود العديد من مشكلات التصميم الرئيسية التي لم يتم حلها والتي تتعلق بتنفيذ مكدسات الخيوط الخضراء .

بعد إزالة الخيوط الخضراء ، بدأ أعضاء مشروع Rust العمل على حل بديل يعتمد على التجريد المستقبلي. في بعض الأحيان يُطلق عليها أيضًا الوعود ، كانت العقود الآجلة ناجحة جدًا في اللغات الأخرى كتجريد قائم على المكتبة لعدم حظر الإدخال والإخراج ، وكان معروفًا أنهم على المدى الطويل يربطون جيدًا بناء جملة غير متزامن / انتظار مما قد يجعلهم أقل ملاءمة من نظام الخيط الأخضر غير مرئي تمامًا.

كان الاختراق الرئيسي في تطوير التجريد المستقبلي هو إدخال نموذج قائم على الاستطلاع للعقود الآجلة. بينما تستخدم اللغات الأخرى نموذجًا قائمًا على رد الاتصال ، حيث يكون المستقبل نفسه مسؤولاً عن جدولة تشغيل رد الاتصال عند اكتماله ، يستخدم Rust نموذجًا قائمًا على الاستطلاع ، حيث يكون المنفذ مسؤولاً عن اقتراع المستقبل حتى الاكتمال ، و في المستقبل ، مجرد إبلاغ المنفذ بأنه مستعد لإحراز مزيد من التقدم باستخدام تجريد Waker. نجح هذا النموذج لعدة أسباب:

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

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

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

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

غير متزامن / انتظار وصف الميزة

المُعدِّل async

يمكن تطبيق الكلمة الرئيسية async في مكانين:

  • قبل تعبير الكتلة.
  • قبل وظيفة حرة أو وظيفة مرتبطة في ضمني متأصل.

_ (مواقع أخرى للوظائف غير المتزامنة - سيتم تطوير طرق الإغلاق الحرفية وطرق السمات ، على سبيل المثال ، بشكل أكبر واستقرارها في المستقبل.) _

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

يقوم المُعدِّل غير المتزامن بإجراء هذا التعديل عن طريق التسبب في تقييم العنصر بدلاً من ذلك باعتباره مُنشئًا خالصًا للمستقبل ، مع أخذ الحجج والتقاطات كحقول للمستقبل. يتم التعامل مع كل نقطة انتظار على أنها متغير منفصل لآلة الحالة هذه ، وطريقة "الاستطلاع" للمستقبل تقدم المستقبل من خلال هذه الحالات بناءً على تحويل الكود الذي كتبه المستخدم ، حتى يصل في النهاية إلى حالته النهائية.

المُعدِّل async move

على غرار عمليات الإغلاق ، يمكن للكتل غير المتزامنة التقاط المتغيرات في النطاق المحيط في حالة المستقبل. مثل عمليات الإغلاق ، يتم التقاط هذه المتغيرات افتراضيًا بالرجوع إليها. ومع ذلك ، يمكن بدلاً من ذلك التقاطها بالقيمة ، باستخدام المُعدِّل move (تمامًا مثل الإغلاق). async قبل move ، مما يجعل هذه الكتل async move { } كتل.

عامل التشغيل await

ضمن سياق غير متزامن ، يمكن تكوين تعبير جديد من خلال دمج تعبير مع عامل التشغيل await ، باستخدام هذه الصيغة:

expression.await

لا يمكن استخدام عامل التشغيل انتظارًا إلا داخل سياق غير متزامن ، ويجب أن يستخدم نوع التعبير المطبق عليه سمة Future . يتم تقييم تعبير انتظار إلى قيمة الإخراج للمستقبل الذي يتم تطبيقه عليه.

يؤدي عامل التشغيل المنتظر إلى التحكم في المستقبل الذي يقيمه السياق غير المتزامن حتى اكتمال المستقبل الذي يتم تطبيقه عليه. لا يمكن كتابة عملية منح التحكم هذه في بناء الجملة السطحي ، ولكن إذا أمكن (باستخدام بناء الجملة YIELD_CONTROL! في هذا المثال) ، فإن إلغاء الانتظار سيبدو تقريبًا كما يلي:

loop {
    match $future.poll(&waker) {
        Poll::Ready(value)  => break value,
        Poll::Pending       => YIELD_CONTROL!,
    }
}

يسمح لك هذا بالانتظار حتى تنتهي العقود الآجلة من التقييم في سياق غير متزامن ، وإعادة توجيه عائد التحكم من خلال Poll::Pending إلى الخارج إلى السياق الخارجي غير المتزامن ، وفي النهاية إلى المنفذ الذي نشأ عليه المستقبل.

نقاط القرار الرئيسية

يستسلم على الفور

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

يختلف هذا عن العديد من اللغات الأخرى ، حيث تبدأ عمليات استدعاء دالة غير متزامنة على الفور. في هذه اللغات الأخرى ، يعتبر غير المتزامن بنية متزامنة بطبيعتها: عندما تستدعي دالة غير متزامنة ، فإنها تطلق مهمة أخرى لبدء التنفيذ المتزامن مع مهمتك الحالية. ومع ذلك ، في Rust ، لا يتم تنفيذ العقود الآجلة بطبيعتها بطريقة متزامنة.

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

المرجعي:

بناء جملة نوع الإرجاع

يستخدم بناء جملة وظائفنا غير المتزامنة نوع الإرجاع "الداخلي" ، بدلاً من نوع الإرجاع "الخارجي". أي أنهم يقولون إنهم يعيدون النوع الذي قاموا بتقييمه في النهاية ، بدلاً من القول إنهم يعيدون مستقبلًا من هذا النوع.

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

ما قلب الموازين حقًا بالنسبة لنا هو مسألة شطب مدى الحياة. نوع الإرجاع "الخارجي" لأي دالة غير متزامنة هو impl Future<Output = T> ، حيث T هو نوع الإرجاع الداخلي. ومع ذلك ، فإن هذا المستقبل يلتقط أيضًا عمر أي وسيطات إدخال في حد ذاته: هذا هو عكس الافتراضي للسمة الضمنية ، والذي لا يُفترض أنه يلتقط أي عمر للإدخال ما لم تحدده. بعبارة أخرى ، قد يعني استخدام نوع الإرجاع الخارجي أن الدوال غير المتزامنة لم تستفد أبدًا من استبعاد مدى الحياة (ما لم نفعل شيئًا أكثر غرابة مثل وجود قواعد استبعاد مدى الحياة تعمل بشكل مختلف للوظائف غير المتزامنة والوظائف الأخرى).

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

طلب المدمر

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

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

(في يوم من الأيام ، قد نكون مهتمين باتباع طرق لتمييز المواد المدمرة على أنها نقية وقابلة لإعادة الترتيب. هذا هو عمل التصميم المستقبلي الذي له آثار لا علاقة لها بالتزامن / الانتظار أيضًا.)

المرجعي:

في انتظار بناء جملة عامل التشغيل

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

منذ عام 2015 ، كان لدى Rust عامل تشغيل postfix ? لمعالجة الأخطاء المريحة. منذ فترة طويلة قبل الإصدار 1.0 ، كان لدى Rust أيضًا عامل تشغيل postfix . للوصول إلى الحقول واستدعاءات الطريقة. نظرًا لأن حالة الاستخدام الأساسية للعقود الآجلة هي إجراء نوع من IO ، فإن الغالبية العظمى من العقود الآجلة يتم تقييمها إلى Result مع بعض
نوع من الخطأ. هذا يعني أنه من الناحية العملية ، يتم تسلسل كل عملية انتظار تقريبًا إما باستخدام ? أو استدعاء طريقة بعد ذلك. نظرًا للأولوية القياسية لمشغلي البادئة وما بعد الإصلاح ، كان من الممكن أن يتسبب ذلك في كتابة كل عامل انتظار تقريبًا (await future)? ، وهو ما نعتبره غير مريح للغاية.

لذلك قررنا استخدام صيغة postfix ، والتي تتكون بشكل جيد جدًا من عوامل التشغيل ? و . . بعد التفكير في العديد من الخيارات النحوية المختلفة ، اخترنا استخدام عامل التشغيل . متبوعًا بالكلمة الأساسية انتظار.

المرجعي:

دعم كل من المنفذين الفرديين ومتعدد الخيوط

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

على غرار السلوك الحالي لبناء جملة impl Trait ، فإن الوظائف غير المتزامنة "تسرب" السمات التلقائية للمستقبل التي تعود. أي ، بالإضافة إلى ملاحظة أن نوع الإرجاع الخارجي هو مستقبل ، يمكن للمتصل أيضًا ملاحظة ما إذا كان هذا النوع هو إرسال أم مزامنة ، بناءً على فحص جسمه. هذا يعني أنه عندما تتم جدولة نوع الإرجاع لـ async fn في منفذ متعدد مؤشرات الترابط ، يمكنه التحقق مما إذا كان هذا آمنًا أم لا. ومع ذلك ، لا يشترط أن يكون النوع إرسال ، وبالتالي يمكن للمستخدمين في المنفذين ذوي الخيوط الواحدة الاستفادة من العناصر الأولية ذات الخيوط الواحدة الأكثر أداءً.

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

المرجعي:

حاصرات الاستقرار المعروفة

حجم الدولة

العدد: # 52924

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

أعمار متعددة في وظائف غير متزامنة

العدد: # 56238

يجب أن تكون الدوال غير المتزامنة قادرة على الحصول على فترات حياة متعددة في توقيعها ، وكلها "يتم التقاطها" في المستقبل يتم تقييم الوظيفة عند استدعائها. ومع ذلك ، فإن التخفيض الحالي إلى impl Future داخل المترجم لا يدعم فترات إدخال متعددة ؛ هناك حاجة إلى إعادة بناء أعمق
هذا العمل. نظرًا لأنه من المرجح جدًا أن يكتب المستخدمون وظائف ذات أعمار إدخال متعددة (ربما تم حذفها بالكامل) ، فهذا يعد إصلاحًا لخلل الحظر.

مشكلات الحظر الأخرى:

ملصق

العمل المستقبلي

كل هذه الامتدادات معروفة وذات أولوية عالية جدًا لـ MVP والتي نعتزم التقاط العمل عليها بمجرد شحن الإصدار الأولي من async / wait.

عمليات الإغلاق غير المتزامن

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

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

دعم عدم وجود الأمراض المنقولة بالاتصال الجنسي

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

على الرغم من أننا لا نحظر تنفيذ هذا التغيير ، إلا أننا نعتبره أولوية عالية لأنه يمنع استخدام غير متزامن / انتظار على الأنظمة التي لا تدعم TLS. هذه مشكلة تنفيذ خالصة: لا شيء في تصميم النظام يتطلب استخدام TLS.

طرق السمات غير المتزامنة

لا نسمح حاليًا بالوظائف أو الأساليب المرتبطة غير المتزامنة في السمات ؛ هذا هو المكان الوحيد الذي يمكنك فيه كتابة fn لكن ليس async fn . من الواضح جدًا أن الأساليب غير المتزامنة ستكون تجريدًا قويًا ونريد دعمها.

سيتم التعامل مع طريقة غير متزامنة وظيفيًا كطريقة تقوم بإرجاع نوع مرتبط من شأنه أن ينفذ في المستقبل ؛ ستولد كل طريقة غير متزامنة نوعًا مستقبليًا فريدًا لجهاز الحالة الذي تترجم إليه هذه الطريقة.

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

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

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

المولدات والمولدات غير المتزامنة

لدينا ميزة مولد غير مستقرة باستخدام نفس تحويل آلة الحالة coroutine لأخذ وظائف تنتج قيمًا متعددة وتحويلها إلى آلات حالة. حالة الاستخدام الأكثر وضوحًا لهذه الميزة هي إنشاء وظائف يتم تجميعها إلى "مكررات" ، تمامًا كما يتم تجميع الدوال غير المتزامنة إلى
الآجلة. وبالمثل ، يمكننا تكوين هاتين الميزتين لإنشاء مولدات غير متزامنة - وظائف تُجمّع إلى "تدفقات" ، المكافئ غير المتزامن للمكرّرات. هناك بالفعل حالات استخدام واضحة لهذا في برمجة الشبكة ، والتي غالبًا ما تتضمن تدفقات من الرسائل التي يتم إرسالها بين الأنظمة.

المولدات لديها الكثير من أسئلة التصميم المفتوحة لأنها ميزة مرنة للغاية مع العديد من الخيارات الممكنة. لا يزال التصميم النهائي للمولدات في Rust من حيث بناء الجملة وواجهات برمجة التطبيقات للمكتبة غير مؤكد.

A-async-await AsyncAwait-Focus F-async_await I-nominated T-lang disposition-merge finished-final-comment-period

التعليق الأكثر فائدة

اكتملت الآن فترة التعليق النهائية ، مع الاستعداد للدمج ، وفقًا للمراجعة أعلاه .

بصفتي الممثل الآلي لعملية الحوكمة ، أود أن أشكر المؤلف على عمله وكل من ساهم.

سيتم دمج RFC قريبًا.

ال 58 كومينتر

تضمينrfcbot fcp

اقترح عضو الفريق withoutboats دمج هذا. الخطوة التالية هي المراجعة من قبل باقي أعضاء الفريق المميزين:

  • [x] @ Centril
  • [x]cramertj
  • [x]eddyb
  • [x] @ joshtriplett
  • [x]nikomatsakis
  • []pnkfelix
  • [x] @ scottmcm
  • [x] @ بدون قوارب

مخاوف:

بمجرد موافقة أغلبية المراجعين (وتكون موافقتان على الأكثر معلقة) ، سيدخل هذا فترة التعليق النهائية. إذا اكتشفت مشكلة كبيرة لم تُثار في أي وقت في هذه العملية ، فيرجى التحدث!

راجع هذا المستند للحصول على معلومات حول الأوامر التي يمكن أن يقدمها لي أعضاء الفريق.

(ما عليك سوى تسجيل أدوات الحظر الموجودة في التقرير أعلاه للتأكد من أنها لا تنزلق)

rfcbot تتعلق بالتنفيذ - العمل - منع - التثبيت

عضو الفريق ... اقترح دمج هذا

كيف يمكن دمج مشكلة في Github (وليس طلب سحب)؟

vi The bot هو مجرد سخيف قليلاً ولا يتحقق مما إذا كانت مشكلة أو PR :) يمكنك استبدال "merge"

واو ، شكرا لك على الملخص الشامل! لقد كنت أتابع بشكل عرضي فقط ، لكنني واثق تمامًا من أنك على رأس كل شيء.

مراجعة rfcbot

هل يمكن إضافة "مشكلات الفرز AsyncAwait-Unclear بشكل صريح" إلى حاصرات التثبيت (و / أو تسجيل القلق بشأن ذلك)؟

لدي https://github.com/rust-lang/rust/issues/60414 الذي أعتقد أنه مهم (من الواضح أنه الخطأ الخاص بي: p) ، وأود على الأقل تأجيله صراحة قبل الاستقرار :)

أود فقط أن أعبر عن شكر المجتمع للجهود التي بذلتها فرق Rust في هذه الميزة! كان هناك الكثير من التصميم والمناقشات وبعض الأعطال في التواصل ، لكنني على الأقل ، وآمل كثيرين آخرين ، أشعر بالثقة من أنه من خلال كل ذلك وجدنا أفضل حل ممكن لـ Rust. : تادا:

(ومع ذلك ، أود أن أرى ذكر المشكلات المتعلقة بسد الجسور إلى واجهات برمجة التطبيقات القائمة على الإكمال ونظام الإلغاء غير المتزامن في الاحتمالات المستقبلية. TL ؛ DR لا يزال يتعين عليهم تمرير المخازن المؤقتة المملوكة. إنها مشكلة مكتبة ، ولكن واحدة مع ذكر).

أود أيضًا أن أرى ذكرًا لمشاكل واجهات برمجة التطبيقات القائمة على الإكمال. (انظر هذا الموضوع الداخلي للاطلاع على السياق) بالنظر إلى IOCP وتقديم io_uring ، والذي قد يصبح الطريق لـ IO غير المتزامن على Linux ، أعتقد أنه من المهم أن يكون لديك طريقة واضحة للمضي قدمًا للتعامل معها. لا يمكن تنفيذ أفكار الإسقاط غير المتزامن الافتراضي من IIUC بأمان ، وسيكون تمرير المخازن المؤقتة المملوكة أقل ملاءمة وربما أقل أداء (على سبيل المثال بسبب موقع أسوأ أو بسبب نسخ إضافية).

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

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

تضمين التغريدة

هل يمكن إضافة "مشكلات الفرز AsyncAwait-Unclear بشكل صريح" إلى حاصرات التثبيت (و / أو تسجيل القلق بشأن ذلك)؟

نعم ، هذا شيء كنا نفعله كل أسبوع. WRT هذه المشكلة المحددة (# 60414) ، أعتقد أنها مهمة وأحب أن أراها ثابتة ، لكننا لم نتمكن بعد من تحديد ما إذا كان يجب منع الاستقرار أم لا ، خاصةً أنه يمكن ملاحظته بالفعل في -> impl Trait وظائف

cramertj شكرا لك! أعتقد أن مشكلة # 60414 هي في الأساس "يمكن أن يظهر الخطأ بسرعة كبيرة الآن" ، بينما مع -> impl Trait يبدو أنه لم يلاحظها أحد من قبل - فلا بأس إذا تم تأجيلها على أي حال ، بعض المشكلات سوف تضطر إلى :) (FWIW نشأت في كود طبيعي في وظيفة حيث أعيد كل من () في مكان ما و T::Assoc في مكان آخر ، مما جعلني IIRC غير قادر على تجميعه - لم تتحقق من الرمز منذ فتح # 60414 ، على الرغم من ذلك ، ربما تكون ذكرياتي خاطئة)

Ekleog نعم هذا منطقي! يمكنني بالتأكيد معرفة سبب الألم - لقد قمت بإنشاء تيار زوليب للتعمق أكثر في هذه المشكلة المحددة.

تحرير: لا تهتم ، لقد فاتني الهدف 1.38 .

تضمين التغريدة

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

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

تضمين التغريدة

يمكن لفريق lang بالطبع أن يحكم على هذا الأمر أفضل مني ، لكن التأخير إلى 1.38 لضمان تطبيق مستقر يبدو أكثر منطقية.

تستهدف هذه المسألة 1.38 ، انظر السطر الأول من الوصف.

@ huxi شكرا ، فاتني ذلك. تحرير تعليقي.

تضمين التغريدة

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

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

(ومع ذلك ، أود أن أرى ذكر المشكلات المتعلقة بسد الجسور إلى واجهات برمجة التطبيقات القائمة على الإكمال ونظام الإلغاء غير المتزامن في الاحتمالات المستقبلية. TL ؛ DR لا يزال يتعين عليهم تمرير المخازن المؤقتة المملوكة. إنها مشكلة مكتبة ، ولكن واحدة مع ذكر).

أود أيضًا أن أرى ذكرًا لمشاكل واجهات برمجة التطبيقات القائمة على الإكمال. (انظر هذا الموضوع الداخلي للسياق) بالنظر إلى IOCP وإدخال io_uring ، والتي قد تصبح الطريق إلى IO غير المتزامن على Linux ، أعتقد أنه من المهم أن يكون لديك طريقة واضحة للمضي قدمًا للتعامل معها.

أتفق مع تايلور في أن مناقشة تصميمات واجهة برمجة التطبيقات في مساحة المشكلة هذه ستكون خارج الموضوع ، لكنني أريد أن أتناول جانبًا محددًا واحدًا من هذه التعليقات (وهذه المناقشة حول io_uring بشكل عام) ذات الصلة بالتثبيت غير المتزامن / انتظار: مشكلة توقيت.

io_uring هي واجهة قادمة إلى Linux هذا العام ، 2019. يعمل مشروع Rust على تجريد العقود الآجلة منذ عام 2015 ، قبل أربع سنوات. وقع الاختيار الأساسي لتفضيل الاستطلاع على أساس واجهة برمجة التطبيقات (API) القائمة على الإنجاز خلال عامي 2015 و 2016. في RustCamp في عام 2015 ، تحدث Carl Lerche عن سبب قيامه بهذا الاختيار في mio ، وهو تجريد IO الأساسي. في منشور المدونة هذا في عام 2016 ، تحدث آرون تورون عن فوائد إنشاء تجريدات ذات مستوى أعلى. لقد تم اتخاذ هذه القرارات منذ وقت طويل ولم يكن من الممكن أن نصل إلى النقطة التي نحن الآن بدونها.

الاقتراحات التي مفادها أنه يجب علينا إعادة النظر في نموذجنا المستقبلي الأساسي هي اقتراحات يجب أن نعود بها إلى الحالة التي كنا فيها قبل 3 أو 4 سنوات ، ونبدأ من جديد من تلك النقطة. ما نوع التجريد الذي يمكن أن يغطي نموذج IO القائم على الإكمال دون تقديم النفقات العامة للأوليات ذات المستوى الأعلى ، مثل وصف آرون؟ كيف سنقوم بتعيين هذا النموذج إلى بناء جملة يتيح للمستخدمين كتابة "الصدأ العادي + التعليقات التوضيحية الثانوية" بالطريقة التي يعمل بها غير المتزامن / الانتظار؟ كيف سنتمكن من دمج ذلك في نموذج ذاكرتنا ، كما فعلنا مع أجهزة الحالة هذه باستخدام دبوس؟ محاولة تقديم إجابات لهذه الأسئلة ستكون خارج موضوع هذا الموضوع ؛ المغزى أن الإجابة عليها ، وإثبات صحة الإجابات ، هو العمل. ما يرقى إلى عقد قوي من سنوات العمل بين مختلف المساهمين حتى الآن يجب إعادة بنائه مرة أخرى.

الهدف من Rust هو شحن منتج يمكن للناس استخدامه ، وهذا يعني أنه يتعين علينا الشحن . لا يمكننا دائمًا التوقف للنظر في المستقبل فيما قد يصبح صفقة كبيرة العام المقبل ، وإعادة تشغيل عملية التصميم الخاصة بنا لدمج ذلك. نحن نبذل قصارى جهدنا بناءً على الموقف الذي نجد أنفسنا فيه. من الواضح أنه قد يكون من المحبط أن نشعر وكأننا بالكاد فوتنا شيئًا كبيرًا ، ولكن كما هو الحال ليس لدينا رؤية كاملة أيضًا أ) لما هو أفضل نتيجة للتعامل مع io_uring سيكون ، ب) مدى أهمية io_uring في النظام البيئي ككل. لا يمكننا التراجع عن 4 سنوات من العمل بناءً على هذا.

توجد بالفعل قيود مماثلة ، وربما أكثر خطورة ، من الصدأ في أماكن أخرى. أريد أن أسلط الضوء على واحدة نظرت إليها مع نيك فيتزجيرالد الخريف الماضي: تكامل wasm GC. تتمثل خطة معالجة الكائنات المُدارة في wasm في تقسيم مساحة الذاكرة بشكل أساسي ، بحيث تكون موجودة في مساحة عنوان منفصلة عن الكائنات غير المُدارة (في الواقع ، في يوم من الأيام ، في العديد من مساحات العناوين المنفصلة). لم يتم تصميم نموذج ذاكرة Rust ببساطة للتعامل مع مساحات عناوين منفصلة ، وأي رمز غير آمن يتعامل مع ذاكرة الكومة اليوم يفترض أن هناك مساحة عنوان واحدة فقط. على الرغم من أننا رسمنا كلاً من الحلول التقنية المتكسرة والحلول التقنية غير القابلة للكسر ولكنها شديدة التعطيل ، فإن المسار الأكثر احتمالاً للمضي قدمًا هو قبول أن قصة wasm GC الخاصة بنا قد لا تكون مثالية تمامًا ، لأننا نتعامل مع قيود Rust مثل إنه موجود.

أحد الجوانب المثيرة للاهتمام التي نجعلها مستقرة هنا هو أننا نجعل هياكل مرجعية ذاتية متاحة من كود آمن. ما يجعل هذا مثيرًا للاهتمام هو أنه في Pin<&mut SelfReferentialGenerator> ، لدينا مرجع قابل للتغيير (مخزن كحقل في Pin ) يشير إلى حالة المولد بالكامل ، ولدينا مؤشر داخل تلك الحالة يشير لقطعة أخرى من الدولة. تلك الأسماء المستعارة للمؤشر الداخلي مع مرجع متغير!

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

ربما يكون هناك القليل مما يمكننا القيام به حيال ذلك في هذه المرحلة ، لا سيما نظرًا لأن Pin مستقر بالفعل ، لكنني أشعر أنه من الجدير الإشارة إلى أن هذا سيعقد بشكل كبير أيًا كانت القواعد التي يتم السماح بالتعريف لها و وهو ليس. إذا كنت تعتقد أن Stacked Borrows معقد ، فاستعد للأمور التي تزداد سوءًا.

نسخة إلى https://github.com/rust-lang/unsafe-code-guidelines/issues/148

لا يتم استخدام المرجع القابل للتغيير ، على حد علمي ، للوصول فعليًا إلى جزء الذاكرة الذي يشير إليه المؤشر إلى حقل آخر.

لقد تحدث الناس عن جعل جميع أنواع coroutine هذه تنفذ Debug ، يبدو أن هذه المحادثة يجب أن تدمج أيضًا إرشادات التعليمات البرمجية غير الآمنة للتأكد من أمان الطباعة.

لقد تحدث الناس عن جعل جميع أنواع coroutine هذه تنفذ Debug ، يبدو أن هذه المحادثة يجب أن تدمج أيضًا إرشادات التعليمات البرمجية غير الآمنة للتأكد من سلامة الطباعة.

في الواقع. مثل هذا التنفيذ Debug ، إذا قام بطباعة الحقول الذاتية المرجعية ، فمن المحتمل أن يحظر التحسينات المستندة إلى المرجع على مستوى MIR داخل المولدات.

تحديث بخصوص أدوات الحظر:

حقق كل من الحاصرات عالية المستوى تقدمًا كبيرًا وقد يتم الانتهاء من كليهما (؟). مزيد من المعلومات منcramertjtmandry وnikomatsakis حول هذا سيكون أمرا رائعا:

  • يجب إصلاح مشكلة الأعمار المتعددة بواسطة # 61775
  • قضية الحجم أكثر غموضا. سيكون هناك دائمًا المزيد من التحسينات التي يجب القيام بها ، لكنني أعتقد أنه تم حل المشكلة في الغالب لتجنب زيادة عدد المسدسات الأسية الواضحة؟

هذا يجعل التوثيق والاختبار بمثابة العوائق الرئيسية لتثبيت هذه الميزة. أعربCentril باستمرار عن مخاوفه من أن الميزة لم يتم اختبارها أو صقلها بشكل جيد ؛ Centril هل هناك أي مكان قمت فيه بتعداد مخاوف معينة يمكن تحديدها لدفع هذه الميزة إلى الاستقرار؟

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

اعتبارًا من اليوم ، لدينا 6 أسابيع حتى يتم قطع الإصدار التجريبي ، لذلك لنفترض أن لدينا 4 أسابيع (حتى 1 أغسطس) لإنجاز هذه الأشياء لنتأكد من أننا لن نتراجع عن 1.38.

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

أعتقد ذلك ، وأغلق البعض الآخر مؤخرًا ؛ ولكن هناك مشكلات أخرى تتعلق بالحظر .

Centril هل هناك أي مكان قمت فيه بتعداد مخاوف معينة يمكن تحديدها لدفع هذه الميزة إلى الاستقرار؟

هناك ورقة صندوق إسقاط تحتوي على قائمة بالأشياء التي أردنا اختبارها وهناك https://github.com/rust-lang/rust/issues/62121. بخلاف ذلك سأحاول إعادة مراجعة المناطق التي أعتقد أنها لم تخضع للاختبار في أسرع وقت ممكن. ومع ذلك ، يتم الآن اختبار بعض المناطق جيدًا.

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

في الواقع؛ سأكون سعيدًا لمراجعة العلاقات العامة للإشارة. أيضا ccehuss.


أرغب أيضًا في نقل async unsafe fn من MVP إلى بوابة الميزات الخاصة به لأنني أعتقد أ) أنه لم يشهد فائدة تذكر ، ب) لم يتم اختباره جيدًا بشكل خاص ، ج) يبدو أنه يتصرف بغرابة لأن .await النقطة ليست المكان الذي تكتب فيه unsafe { ... } وهذا مفهوم من "تسرب تنفيذ POV" ولكن ليس كثيرًا من تأثيرات POV ، د) لقد شهدت القليل من المناقشة ولم يتم تضمينها في RFC ولا هذا التقرير ، و هـ) قمنا بهذا باستخدام const fn وقد نجح الأمر. (يمكنني كتابة خاصية بوابة العلاقات العامة)

أنا بخير مع زعزعة استقرار async unsafe fn ، على الرغم من أنني متشكك في أن ننتهي بتصميم مختلف عن التصميم الحالي. ولكن يبدو من الحكمة أن نمنحنا الوقت لمعرفة ذلك!

لقد أنشأت https://github.com/rust-lang/rust/issues/62500 لنقل async unsafe fn إلى بوابة ميزة مميزة وأدرجتها على أنها مانع. من المحتمل أن ننشئ مشكلة تتبع مناسبة أيضًا ، على ما أعتقد.

أنا متشكك بشدة في أننا سنصل إلى تصميم مختلف مقابل async unsafe fn وأندهش من قرار عدم إدراجه في الجولة الأولى من التثبيت. لقد كتبت عددًا من async fn s غير آمنة وستجعلها async fn really_this_function_is_unsafe() أو شيء من هذا القبيل ، على ما أعتقد. يبدو هذا بمثابة انحدار في توقع أساسي لدى مستخدمي Rust من حيث القدرة على تحديد الوظائف التي تتطلب unsafe { ... } للاتصال. ستساهم بوابة ميزة أخرى في الانطباع بأن async / await غير مكتمل.

cramertj يبدو أننا يجب أن نناقش! لقد أنشأت موضوع Zulip له ، لمحاولة منع مشكلة التعقب هذه من التحميل الزائد.

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

لدي فكرة عن كيفية إصلاح هذه المشكلة ، ولكن ما لم تكن هذه الطريقة أكثر شيوعًا مما أدركت ، فمن المحتمل ألا تكون مانعًا لـ MVP المستقر.

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

cramertj (تذكير: أنا أستخدم غير متزامن / انتظر async unsafe الآن بدون تجربة وفكر مناسبين.

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

[ملاحظة جانبية لا تستحق المناقشة هنا حقًا: لأن "هناك بوابة ميزة أخرى ستساهم في الانطباع بأن عدم التزامن / الانتظار غير منتهي" ، وجدت خطأً كل بضع ساعات من استخدام غير متزامن / انتظار ، ينتشر بواسطة عدد قليل أشهر مطلوبة بشكل شرعي من قبل فريق rustc لإصلاحها ، وهذا هو الشيء الذي يجعلني أقول إنه غير مكتمل. تم إصلاح آخر واحد قبل بضعة أيام ، وآمل حقًا ألا أكتشف رمزًا آخر عندما أحاول مرة أخرى تجميع الكود الخاص بي باستخدام rustc أحدث ، ولكن ...]

تبدو حجتك كأنها حجة لتأخير تثبيت عدم التزامن / انتظار ، وليس لتثبيت عدم التزامن غير الآمن الآن دون تجربة وفكر مناسبين.

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

لا أستطيع تخيل أي تصميم آخر لذلك

تصميم بديل ، على الرغم من أنه يتطلب بالتأكيد امتدادات معقدة: async unsafe fn هو unsafe إلى .await ، وليس call() . السبب وراء ذلك هو أنه لا يمكن فعل أي شيء غير آمن في النقطة التي يتم فيها استدعاء async fn وإنشاء impl Future . كل ما تفعله هذه الخطوة هو تجميع البيانات في بنية (في الواقع ، كل async fn هي const للاتصال). النقطة الفعلية لعدم الأمان هي التقدم بالمستقبل بـ poll .

(imho ، إذا كان unsafe فوريًا ، فإن unsafe async fn أكثر منطقية ، وإذا تأخر unsafe ، فإن async unsafe fn أكثر منطقية.)

بالطبع ، إذا لم نحصل أبدًا على طريقة لنقول على سبيل المثال ، unsafe Future حيث تكون جميع طرق Future غير آمنة للاتصال ، فإن "رفع" unsafe لإنشاء impl Future ، وعقد ذلك unsafe هو استخدام المستقبل الناتج بطريقة آمنة. ولكن يمكن أيضًا القيام بذلك بشكل تافه تقريبًا بدون unsafe async fn بمجرد "إزالة الحل" يدويًا إلى كتلة async : unsafe fn os_stuff() -> impl Future { async { .. } } .

علاوة على ذلك ، هناك سؤال حول ما إذا كانت هناك بالفعل طريقة للحصول على ثوابت يجب الاحتفاظ بها بمجرد بدء poll ing والتي لا تحتاج إلى الاحتفاظ بها عند الإنشاء. من الشائع في Rust استخدام مُنشئ unsafe لنوع آمن (مثل Vec::from_raw_parts ). ولكن المفتاح هناك أنه بعد البناء ، النوع _ لا يمكن_ إساءة استخدامه ؛ انتهى نطاق unsafe . إن تحديد نطاق عدم الأمان هذا هو مفتاح ضمانات Rust. إذا قدمت unsafe async fn الذي يصنع صندوقًا آمنًا impl Future مع متطلبات كيفية / وقت الاستقصاء ، ثم مرره إلى رمز آمن ، فهذا الرمز الآمن يكون فجأة داخل حاجز عدم الأمان. ومن المحتمل جدًا أن يحدث هذا بمجرد استخدامك لهذا المستقبل بأي طريقة بخلاف انتظاره فورًا ، حيث من المحتمل أن يمر عبر _ بعض_ المندمج الخارجي.

أعتقد أن TL ؛ DR من هذا هو أن هناك بالتأكيد زوايا async unsafe fn يجب مناقشتها بشكل صحيح قبل تثبيتها ، خاصة مع اتجاه const Trait يُحتمل أن يتم تقديمه (لدي مسودة مدونة منشور حول تعميم هذا على نظام "تأثيرات ضعيف" باستخدام أي كلمة رئيسية معدلة fn ). ومع ذلك ، قد يكون unsafe async fn واضحًا بدرجة كافية حول "ترتيب" / "وضع" unsafe لتحقيق الاستقرار.

أعتقد أن سمة unsafe Future القائمة على التأثيرات ليست فقط بعيدة عن متناول أي شيء نعرف كيفية التعبير عنه في اللغة أو المترجم اليوم ، ولكن سيكون في النهاية تصميمًا أسوأ بسبب التأثير الإضافي- تعدد الأشكال الذي قد يتطلب وجود أدوات دمج.

لا يمكن عمل أي شيء غير آمن في النقطة التي يتم فيها استدعاء fn غير المتزامن وإنشاء المستقبل الضمني. كل ما تفعله هذه الخطوة هو حشو البيانات في بنية (في الواقع ، كل fn غير المتزامن ثابت للاتصال). النقطة الفعلية لعدم الأمان هي التقدم بالمستقبل بالاقتراع.

صحيح أنه نظرًا لأن async fn لا يمكنه تشغيل أي كود مستخدم قبل أن يكون .await ed ، فمن المحتمل أن يتأخر أي سلوك غير محدد حتى يتم استدعاء .await . أعتقد ، مع ذلك ، أن هناك فرقًا مهمًا بين نقطة UB ونقطة unsafe ty. النقطة الفعلية لـ unsafe ty هي المكان الذي يقرر فيه مؤلف واجهة برمجة التطبيقات أن المستخدم يحتاج إلى الوعد باستيفاء مجموعة من الثوابت غير القابلة للتحقق منها بشكل ثابت ، حتى لو كانت نتيجة انتهاك هذه الثوابت لن تتسبب في UB حتى وقت لاحق في بعض التعليمات البرمجية الآمنة الأخرى. أحد الأمثلة الشائعة على ذلك هو دالة unsafe لإنشاء قيمة تنفذ سمة بطرق آمنة (بالضبط ما هذا). لقد رأيت هذا مستخدمًا للتأكد من أنه على سبيل المثال Visitor - أنواع التنفيذ التي تعتمد تطبيقاتها على ثوابت unsafe يمكن استخدامها بشكل سليم ، من خلال طلب unsafe لإنشاء النوع. تتضمن الأمثلة الأخرى أشياء مثل slice::from_raw_parts ، والتي لن تتسبب في حد ذاتها في UB (باستثناء ثوابت الصلاحية) ، ولكن الوصول إلى الشريحة الناتجة سيفعل ذلك.

لا أعتقد أن async unsafe fn يمثل حالة فريدة أو مثيرة للاهتمام هنا - فهو يتبع نمطًا راسخًا لأداء سلوك unsafe خلف واجهة آمنة من خلال طلب unsafe البناء.

cramertj حقيقة أنك للجدل حول هذا (وأنا لا أقترح أن الحل الحالي هو حل سيئ ، أو أن لدي فكرة أفضل) تعني ، بالنسبة لي ، أن هذا النقاش يجب أن يكون في يجب على الأشخاص الذين يهتمون بالصدأ اتباع: مستودع RFC.

للتذكير ، اقتباس من الملف التمهيدي:

تحتاج إلى اتباع هذه العملية إذا [...]:

  • أي تغيير دلالي أو نحوي للغة لا يعد خطأً.
  • [... وأيضًا أشياء لم يتم الاستشهاد بها]

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

في بعض الأحيان قد يكون عدم اتباع العملية منطقيًا. هنا لا أستطيع أن أرى أي إلحاح من شأنه أن يبرر تجاهل العملية لمجرد تجنب حوالي أسبوعين من تأخير FCP.

لذا من فضلك دع الصدأ يكون صادقًا مع مجتمعه حول الوعود التي يقدمها في الملف التمهيدي الخاص به ، واحتفظ بهذه الميزة أسفل بوابة الميزات حتى يكون هناك على الأقل RFC مقبول ونأمل أن يكون هناك المزيد من الاستخدام في البرية. سواء كانت بوابة ميزة غير متزامنة / انتظار أو مجرد بوابة ميزة غير آمنة غير متزامنة ، فأنا لا أهتم ، ولكن فقط لا أقوم بتثبيت شيء لم يشهد (AFAIK) استخدامًا يذكر فيما وراء غير المتزامن - wg وبالكاد معروف عنه في المجتمع بشكل عام.

أنا أكتب أول تمريرة في المواد المرجعية للكتاب. على طول الطريق ، لاحظت أن RFC المنتظر غير المتزامن يقول أن سلوك المشغل ? لم يتم تحديده بعد. ومع ذلك ، يبدو أنه يعمل بشكل جيد في ساحة لعب غير متزامنة. هل يجب أن ننقل ذلك إلى بوابة ميزة منفصلة؟ أم تم حل ذلك في مرحلة ما؟ لم أشاهده في تقرير الاستقرار ، لكن ربما فاتني ذلك.

(لقد طرحت أيضًا هذا السؤال على Zulip وأفضل الردود هناك ، لأنه من الأسهل إدارتها بالنسبة لي).

نعم ، لقد تمت مناقشتها وحلها جنبًا إلى جنب مع سلوك return ، break ، continue et. آل. وكلها تفعل "الشيء الوحيد الممكن" وتتصرف كما لو كانت داخل الإغلاق.

let f = unsafe { || {...} }; آمن أيضًا للاتصال و IIRC يعادل نقل unsafe إلى داخل الإغلاق.
نفس الشيء لـ unsafe fn foo() -> impl Fn() { || {...} } .

هذه ، بالنسبة لي ، سابقة كافية لـ "يحدث الشيء غير الآمن بعد ترك النطاق unsafe ".

الشيء نفسه ينطبق على أماكن أخرى. كما أشرنا سابقًا ، فإن unsafe ليس دائمًا المكان الذي سيكون فيه UB المحتمل. مثال:

    let mut vec: Vec<u32> = Vec::new();

    unsafe { vec.set_len(100); }      // <- unsafe

    let val = vec.get(5).unwrap();     // <- UB
    println!("{}", val);

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

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

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

async unsafe fn

تعد fns غير الآمنة غير المتزامنة وظائف غير متزامنة لا يمكن استدعاؤها إلا داخل كتلة غير آمنة. يتم التعامل مع داخل أجسامهم على أنها نطاق غير آمن. ان تصميم بديل الأساسي هو جعل المتزامن غير آمنة FNS غير آمنة للانتظار، بدلا من الدعوة. هناك عدد من الأسباب القوية لتفضيل التصميم الذي يكون من غير الآمن الاتصال به:

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

rfcbot اسأل lang "هل نقبل الاستقرار غير المتزامن fn باعتباره fn غير متزامن وغير آمن للاتصال به؟"

ليس لدي أي فكرة عن كيفية إجراء استطلاع باستخدام rfcbot لكني قمت بترشيحه على الأقل.

سأل عضو الفريق

"هل نقبل استقرار fn غير المتزامن باعتباره fn غير متزامن وغير آمن للاتصال به؟"

  • [x] @ Centril
  • [x]cramertj
  • [x]eddyb
  • [] @ joshtriplett
  • [x]nikomatsakis
  • []pnkfelix
  • [] @ scottmcm
  • [x] @ بدون قوارب

تضمين التغريدة

أرغب في أخذ طعنة في نقطة إجماع منظمة حول هذه المشكلة من fns غير الآمن غير المتزامن ، لذلك هذا منشور ملخص مع استطلاع.

شكرا على الكتابة حتى. لقد اقتنعتني المناقشة أن async unsafe fn كما يعمل ليلاً اليوم يتصرف بشكل صحيح. (ربما يجب إضافة بعض الاختبارات نظرًا لأنها تبدو متفرقة.) أيضًا ، هل يمكنك تعديل التقرير في الجزء العلوي بأجزاء من تقريرك + وصف لكيفية تصرف async unsafe fn ؟

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

باعتباري شخصًا لا يولي اهتمامًا كبيرًا ، سأوافق وأعتقد أن الحل هنا هو توثيق جيد.

قد أكون خارج العلامة هنا ، لكن بالنظر إلى ذلك

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

يبدو لي أن الثوابت التي تعتمد على الاستخدام / السلوك المنتظر المحدد تقع في مكان ما بين فكرة سيئة ومن المستحيل الحكم بأمان.

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

struct UnsafeOutput<T>(T);
impl<T> UnsafeOutput<T> {
    unsafe fn unwrap(self) -> T { self.0 }
}

نظرًا لأن unsafe ness يقع قبل async ness في هذا "غير الآمن المبكر" ، سأكون أكثر سعادة لأن طلب التعديل هو unsafe async fn من async unsafe fn ، لأن unsafe (async fn) يرسم بوضوح أكثر على هذا السلوك من async (unsafe fn) .

سوف أقبل أيًا منهما بسعادة ، لكنني أشعر بشدة أن طلب التغليف المعروض هنا يحتوي على unsafe في الخارج ، ويمكن أن يساعد ترتيب المُعدِّلات في توضيح ذلك. ( unsafe هو المُعدِّل إلى async fn ، وليس async المُعدِّل إلى unsafe fn .)

سوف أقبل أيًا منهما بسعادة ، لكنني أشعر بشدة أن طلب التغليف المعروض هنا يحتوي على unsafe في الخارج ، ويمكن أن يساعد ترتيب المُعدِّلات في توضيح ذلك. ( unsafe هو المُعدِّل إلى async fn ، وليس async المُعدِّل إلى unsafe fn .)

كنت معك حتى آخر نقطة بين قوسين. توضح كتابةwithoutboats بالنسبة لي أنه إذا تم التعامل مع عدم الأمان في موقع الاتصال ، فإن ما لديك في الواقع هو unsafe fn (ويصادف أن يتم استدعاؤه في سياق غير متزامن).

أود أن أقول إننا نرسم الدراجة النارية async unsafe fn .

أعتقد أن async unsafe fn أكثر منطقية ، لكنني أعتقد أيضًا أنه يجب علينا قبول أي ترتيب نحويًا بين غير متزامن وغير آمن وثابت. لكن async unsafe fn أكثر منطقية بالنسبة لي مع فكرة أنك تجرد عدم التزامن وتعديل نوع الإرجاع إلى "desugar".

البديل غير قابل للتطبيق على المدى القريب أو المتوسط ​​(أي عدة سنوات). لا توجد طريقة لإنشاء مستقبل غير آمن للاقتراع بلغة Rust المصممة حاليًا.

FWIW واجهت مشكلة مماثلة ذكرتها في RFC2585 عندما يتعلق الأمر بالإغلاق داخل unsafe fn وسمات الوظيفة. لم أكن أتوقع أن يقوم unsafe async fn بإرجاع Future باستخدام طريقة poll آمنة ، ولكن بدلاً من ذلك يتم إرجاع UnsafeFuture مع unsafe طريقة الاستطلاع. (*) يمكننا بعد ذلك أن نجعل .await يعمل أيضًا على UnsafeFuture s عند استخدامه داخل كتل unsafe { } ، لكن ليس بخلاف ذلك.

ستكون هاتان السمتان المستقبليتان تغييرًا كبيرًا فيما يتعلق بما لدينا اليوم ، ومن المحتمل أن تقدم الكثير من مشكلات التركيب. لذا من المحتمل أن تكون سفينة استكشاف البدائل قد أبحرت. نظرًا لأن هذا سيكون مختلفًا عن كيفية عمل سمات Fn اليوم (على سبيل المثال ، ليس لدينا سمة UnsafeFn أو ما شابه ذلك ، وكانت مشكلتي في unsafe fn يُرجع impls Fn() ، أي أنه آمن للاتصال به ، على الرغم من أن هذا الإغلاق يمكن أن يستدعي وظائف غير آمنة.

إنشاء المستقبل "غير الآمن" أو الإغلاق ليس هو المشكلة ، المشكلة هي الاتصال بهم دون إثبات أن القيام بذلك آمن ، خاصة عندما لا تقول أنواعهم أنه يجب القيام بذلك.

(*) يمكننا توفير أداة شاملة UnsafeFuture لجميع Future s ، ويمكننا أيضًا توفير طريقة UnsafeFuture و unsafe لـ "فك" نفسها باعتباره Future آمن لـ poll .

هذا هو سنتي:

  • يقنعني تفسير وظائف غير unsafe هي التصميم الصحيح.
  • أفضّل بشدة الترتيب الثابت للكلمات الرئيسية unsafe و async
  • أنا أفضل طلب unsafe async fn قليلاً لأن الطلب يبدو أكثر منطقية. على غرار "السيارة الكهربائية السريعة" مقابل "السيارة الكهربائية السريعة". ويرجع ذلك أساسًا إلى أن async fn desugars إلى fn . لذلك ، من المنطقي أن تكون الكلمتان الرئيسيتان بجوار بعضهما البعض.

أعتقد أن let f = unsafe { || { ... } } يجب أن يجعل f آمنًا ، ولا يجب أبدًا تقديم سمة UnsafeFn ويجب أن تكون السمة المسبقة .await ing و async unsafe fn آمنة. أي UnsafeFuture يحتاج إلى مبرر قوي!

كل هذا يتبع لأن unsafe يجب أن يكون صريحًا ، ويجب أن يعيدك Rust إلى أرض آمنة. أيضًا من خلال هذا الرمز ، يجب أن يكون f s ... _not_ كتلة غير آمنة ، يجب اعتماد https://github.com/rust-lang/rfcs/pull/2585 و async unsafe fn يجب أن يكون لها جسد آمن.

أعتقد أن هذه النقطة الأخيرة قد تكون حاسمة إلى حد ما. من المحتمل أن يستخدم كل async unsafe fn كتلة unsafe ، ولكن بالمثل سيستفيد معظمهم من بعض تحليلات السلامة ، والعديد منها يبدو معقدًا بما يكفي لأخطاء سهلة.

يجب ألا نتجاوز مدقق الاستعارة أبدًا عند التقاط الإغلاق على وجه الخصوص.

لذا فإن تعليقي هنا: https://github.com/rust-lang/rust/issues/62149#issuecomment -511116357 فكرة سيئة للغاية.

تتطلب السمة UnsafeFuture من المتصل كتابة unsafe { } للاقتراع في المستقبل ، ومع ذلك ليس لدى المتصل أي فكرة عن الالتزامات التي يجب إثباتها هناك ، على سبيل المثال ، إذا حصلت على Box<dyn UnsafeFuture> هل unsafe { future.poll() } آمن؟ لجميع العقود الآجلة؟ لا يمكنك أن تعرف. لذلك سيكون هذا عديم الفائدة تمامًا كما أشار rpjohnst إلى الخلاف UnsafeFn مماثلة.

إن مطالبة المستقبل بأن يكون آمنًا دائمًا أمر منطقي ، وعملية بناء مستقبل يجب أن يكون آمنًا لاستطلاع الرأي يمكن أن تكون غير آمنة ؛ أفترض أن هذا هو async unsafe fn . ولكن في هذه الحالة ، يمكن للعنصر fn توثيق ما يجب دعمه حتى يكون المستقبل المرتجع آمنًا للاستقصاء.

rfcbot تنفيذ-عمل-منع-استقرار

لا يزال هناك نوعان من حاصرات التنفيذ المعروفة على حد علمي (https://github.com/rust-lang/rust/issues/61949 ، https://github.com/rust-lang/rust/issues/62517) وستكون كذلك لا يزال من الجيد إضافة بعض الاختبارات. أنا أقوم بحل مشكلتي لجعل rfcbot ليس مانعًا زمنيًا لدينا ومن ثم سنقوم بالفعل بحظر الإصلاحات بدلاً من ذلك.

rfcbot حل التنفيذ-العمل-منع-الاستقرار

: bell: هذا يدخل الآن فترة التعليق النهائية ، وفقًا للمراجعة أعلاه . :جرس:

العلاقات العامة المقدمة لتحقيق الاستقرار في https://github.com/rust-lang/rust/pull/63209.

اكتملت الآن فترة التعليق النهائية ، مع الاستعداد للدمج ، وفقًا للمراجعة أعلاه .

بصفتي الممثل الآلي لعملية الحوكمة ، أود أن أشكر المؤلف على عمله وكل من ساهم.

سيتم دمج RFC قريبًا.

أحد الجوانب المثيرة للاهتمام التي نجعلها مستقرة هنا هو أننا نجعل هياكل مرجعية ذاتية متاحة من كود آمن. ما يجعل هذا مثيرًا للاهتمام هو أنه في Pin <& mut SelfReferentialGenerator> ، لدينا مرجع قابل للتغيير (مخزن كحقل في Pin) يشير إلى حالة المولد بالكامل ، ولدينا مؤشر داخل تلك الحالة يشير إلى جزء آخر من الحالة . تلك الأسماء المستعارة للمؤشر الداخلي مع مرجع متغير!

كمتابعة لذلك ، تمكنت comex بالفعل من كتابة بعض كود Rust غير المتزامن (الآمن) الذي ينتهك تعليقات LLVM noalias بالطريقة التي نبعث بها بها حاليًا. ومع ذلك ، يبدو أنه بسبب استخدام TLS ، لا يوجد حاليًا أي أخطاء في التجميع.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات