تأمل هذه الدالة، التي ترسل طلب GET إلى عنوان URL وتعيد رمز حالة HTTP. باستخدام HTTP/1 (GODEBUG=http2client=0)، يستغرق استدعاؤها 100 مرة مقابل index.golang.org نحو 710 ملي ثانية على Go 1.26 في جهاز المؤلف. أما على Go 1.27 فيستغرق البرنامج نفسه نحو 150 ملي ثانية، أي أسرع بنحو 5 مرات تقريبًا.
ينشأ هذا الفارق من تكلفة إنشاء الاتصالات. يتطلب الطلب عبر اتصال جديد مصافحة TCP (زمن ذهاب وإياب واحد، أو RTT)، ومصافحة TLS (2 RTT في TLS 1.2)، ثم طلب HTTP نفسه، أي ما مجموعه نحو 3 RTT. وفي الاتصالات بين المناطق الجغرافية، كثيرًا ما تبلغ زمن الاستجابة أحادي الاتجاه 50 ملي ثانية أو أكثر، لذلك قد تكلّف عملية الإعداد وحدها نحو 300 ملي ثانية. وحتى مع index.golang.org، الذي يستخدم TLS 1.3 ويتميز بزمن استجابة منخفض نسبيًا، يظل فتح اتصال جديد ملحوظًا جدًا.
ولتجنب هذه التكلفة، تحاول عملاء HTTP والخوادم إعادة استخدام الاتصالات. يفعّل عملاء HTTP/1.0 والخوادم ذلك بترويسة Connection: keep-alive، بينما تكون اتصالات HTTP/1.1 مستمرة افتراضيًا. ويقوم HTTP/2 بتعدد الإرسال، فيرسل عدة طلبات واستجابات عبر اتصال TCP واحد.
ومع ذلك، قد تفشل إعادة الاستخدام في HTTP/1. فالاستجابات على الاتصال نفسه تُرسل بالتتابع، لذا لا يستطيع net/http تحديد بداية الاستجابة التالية إلا بعد قراءة جسم الاستجابة الحالية حتى نهايته. وفي المثال، لا يُقرأ جسم الاستجابة أبدًا، لذلك عند استدعاء resp.Body.Close يجد net/http جسمًا غير مقروء ولا يستطيع إعادة استخدام الاتصال بأمان. وحتى Go 1.26، كان هذا يفرض إنشاء اتصال جديد لكل طلب.
المصدر: Hacker News · لخّصه HeadlinesBriefing