کاهش مصرف حافظه HttpClient در داتنت 10
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۲/۰۹ ۱۲:۳۴
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
HttpClient به عنوان یکی از ابزارهای اصلی برای ارسال درخواستهای اچتیتیپی (HTTP Requests) و دریافت پاسخها، نقش مهمی در توسعه برنامههای مبتنی بر وب ایفا میکند. با این حال، مدیریت نادرست این کلاس میتواند منجر به مصرف غیرضروری حافظه و کاهش کارایی شود. در نسخه جدید داتنت 10، بهبودهای قابل توجهی در کلاس HttpClient اعمال شده است که به طور خاص بر کاهش مصرف حافظه در سناریوهای استریمینگ (Streaming) تمرکز دارند. این مقاله به بررسی این بهبودها، مکانیزمهای فنی آنها، و تأثیراتشان بر عملکرد برنامهها میپردازد. HttpClient برای ارسال درخواستهای اچتیتیپی و دریافت پاسخها از منابعی که با یک آدرس یوآرآی (URI) شناسایی میشوند، طراحی شده است. این کلاس به دلیل استفاده گسترده در برنامههای وب و سرویسهای ابری، باید به طور کارآمد منابع سیستمی را مدیریت کند. یکی از چالشهای اصلی در نسخههای قبلی داتنت، مدیریت بافر (Buffer) در هنگام استریمینگ پاسخهایی بود که طول محتوای آنها (Content Length) از قبل مشخص نبود. در چنین سناریوهایی، بافر ممکن بود چندین بار تغییر اندازه دهد (Resize)، که این فرآیند به تخصیص مکرر حافظه (Memory Allocation) و افزایش فشار بر جمعآوری زباله (Garbage Collection) منجر میشد. این مشکل به ویژه در پاسخهای بزرگ، مانند دانلود فایلهای چند مگابایتی یا استریمینگ دادههای حجیم، مشهود بود.Content-Length در پاسخ وجود دارد و اندازه دادهها از قبل معلوم است. در این حالت، HttpClient میتواند بافر را با اندازه مناسب تخصیص دهد.Content-Length غایب است، مانند سناریوهای استریمینگ یا پاسخهای تولیدشده به صورت پویا. در این موارد، بافر ممکن است بارها تغییر اندازه دهد، که باعث افزایش مصرف حافظه و کاهش عملکرد میشود.HttpClient به طور خاص در متدهایی مانند GetAsync و GetByteArrayAsync قابل مشاهده است. این متدها برای دریافت پاسخهای اچتیتیپی استفاده میشوند و در داتنت 10 بهینهسازیهایی در مصرف حافظه و سرعت اجرا دریافت کردهاند. جدول زیر، که از یک درخواست کشش (Pull Request) در گیتهاب استخراج شده، عملکرد این متدها را قبل و بعد از بهبودها مقایسه میکند:| متد | نسخه | طول داده (بایت) | میانگین زمان (نانوثانیه) | نسبت | حافظه تخصیصیافته (کیلوبایت) | نسبت تخصیص |
| GetByteArrayAsync | Main | 10,000 | 1,114.6 | 1.00 | 10.81 | 1.00 |
| GetByteArrayAsync | PR | 10,000 | 994.3 | 0.89 | 10.84 | 1.00 |
| GetAsync | Main | 10,000 | 1,284.7 | 1.00 | 28.93 | 1.00 |
| GetAsync | PR | 10,000 | 1,018.1 | 0.79 | 10.84 | 0.37 |
| GetByteArrayAsync | Main | 1,000,000 | 127,633.7 | 1.00 | 978.16 | 1.00 |
| GetByteArrayAsync | PR | 1,000,000 | 110,941.5 | 0.87 | 978.11 | 1.00 |
| GetAsync | Main | 1,000,000 | 151,716.7 | 1.00 | 2,032.28 | 1.00 |
| GetAsync | PR | 1,000,000 | 110,231.7 | 0.73 | 978.1 | 0.48 |
| GetAsync | Main | 100,000,000 | 25,177,538.4 | 1.00 | 260,446.05 | 1.00 |
| GetAsync | PR | 100,000,000 | 16,487,114.6 | 0.66 | 97,657.69 | 0.37 |
GetAsync در سناریوهای با دادههای بزرگ (مانند 100 مگابایت) تا 34 درصد سریعتر عمل میکند (نسبت 0.66).GetAsync تا 63 درصد کاهش یافته است (نسبت تخصیص 0.37).HttpClient محقق شدهاند.HttpClient برای دانلود یک فایل بزرگ استفاده میکند:using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
using var client = new HttpClient();
var response = await client.GetAsync("https://example.com/largefile", HttpCompletionOption.ResponseHeadersRead);
using var stream = await response.Content.ReadAsStreamAsync();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// پردازش دادهها
}
}
}GetAsync با گزینه HttpCompletionOption.ResponseHeadersRead استفاده شده است تا پاسخ به صورت استریمینگ دریافت شود. در داتنت 10، بافرهای مورد استفاده در فرآیند استریمینگ از یک استخر بافر مدیریتشده تأمین میشوند، که باعث کاهش تخصیصهای مکرر حافظه و بهبود عملکرد میشود.HttpClient در داتنت 10 بخشی از تلاش گستردهتر مایکروسافت برای بهینهسازی عملکرد چارچوب داتنت است. برای مثال، در نسخههای قبلی (مانند داتنت 8 و 9)، شاهد معرفی متریکهای داخلی (Built-in Metrics) برای نظارت بر عملکرد HttpClient و بهبودهای مربوط به اتصال چندگانه اچتیتیپی/3 (HTTP/3) بودیم. این تغییرات، در کنار بهینهسازیهای داتنت 10، امکان ساخت برنامههای مقیاسپذیرتر و کارآمدتر را فراهم میکنند.IHttpClientFactory همچنان به عنوان بهترین روش برای مدیریت نمونههای HttpClient توصیه میشود. این کارخانه (Factory) با مدیریت چرخه حیات (Lifetime Management) نمونهها و استفاده از تنظیماتی مانند PooledConnectionLifetime، به توسعهدهندگان کمک میکند تا از مشکلات مرتبط با تغییرات دیاناس (DNS Changes) و مصرف بیش از حد پورتها جلوگیری کنند.HttpClient در داتنت 10، توسعهدهندگان باید به نکات زیر توجه کنند:GetAsync با گزینه HttpCompletionOption.ResponseHeadersRead برای استریمینگ پاسخهای بزرگ استفاده کنید.HttpClient به درستی پیکربندی شدهاند و از بازیافت (Pooling) مناسب برای کاهش سربار استفاده میشود.HttpClient، گام مهمی در جهت کاهش مصرف حافظه و بهبود عملکرد برنامههای مبتنی بر وب برداشته است. رویکرد جدید مبتنی بر استخر بافر، به ویژه در سناریوهای استریمینگ بدون طول مشخص، سربار تخصیص حافظه را به طور قابل توجهی کاهش داده و زمان اجرا را بهبود بخشیده است. این تغییرات، همراه با سایر بهینهسازیهای چارچوب داتنت، توسعهدهندگان را قادر میسازد تا برنامههایی مقیاسپذیرتر و کارآمدتر بسازند. با بهکارگیری بهترین روشها، مانند استفاده از IHttpClientFactory و پیکربندی مناسب نمونههای HttpClient، توسعهدهندگان میتوانند از مزایای کامل این بهبودها بهرهمند شوند.