روش متداول تنظیمات EF Core در برنامههای ASP.NET Core، به صورت معرفی یک DbContext سفارشی، به سیستم تزریق وابستگیهای آن است و سپس میتوان به وهلهای از این Context، توسط تزریق آن به سازندههای کلاسهای مختلف برنامه، دسترسی یافت. به این معنا که به ازای هر درخواست رسیده، یک وهلهی جدید از DbContext ایجاد خواهد شد. در نگارش 2، روش جدیدی برای ثبت DbContext برنامه معرفی شدهاست که در صورت بکارگیری آن، بجای وهله سازی مجدد Contextها، ابتدا استخر موجود Contextها بررسی میشود و در صورت مهیا بودن نمونهای، بجای نمونه سازی از صفر آن، از این نمونهی موجود، استفادهی مجدد خواهد شد. در پایان کار درخواست، تنها وضعیت این Context به حالت اولیه برگردانده شده و سپس به استخر Contextها برای استفادهی مجدد بازگشت داده میشود. این مفهوم درحقیقت پیاده سازی مفهوم connection pooling موجود در ADO.NET است. به این ترتیب هزینهی ساخت و ایجاد اتصالات به بانک اطلاعاتی به شدت کاهش خواهد یافت.
نحوهی معرفی DbContext pooling
اینبار بجای روش قبلی و استفاده از متد AddDbContext
از متد جدید AddDbContextPool استفاده میشود:
محدودیتهای روش DbContext pooling
در حالت استفادهی از روش AddDbContextPool، دیگر متد OnConfiguring کلاس Context سفارشی شما فراخوانی نخواهد شد. بنابراین تمام تنظیمات ابتدایی برنامه را باید به همان کلاس آغازین برنامه منتقل کنید و کلاس Context، این تنظیمات را به صورت ذیل از طریق سازندهی آن دریافت میکند:
همچنین باید درنظر داشت که استفادهی مجدد از یک Context به معنای حفظ مقادیر فیلدهای private کلاس Context سفارشی شما نیز میشود. در اینجا پس از پایان هر درخواست، تنها وضعیت Context از دیدگاه EF به حالت اول بازگشت داده میشود؛ اما حالت شیء Context و تمام اطلاعات فیلدهای خصوصی آن در همان حالت قبلی (و همان وهلهی موجود پیشین و اصلی) رها میشوند. چون وهله سازی مجددی از آن صورت نخواهد گرفت.
یک مثال: بررسی بهبود کارآیی برنامه در حالت استفادهی از DbContext pooling
کدهای کامل این مثال را برای اجرا میتوانید از اینجا دریافت کنید: ContextPooling.zip
در اینجا یکبار حالت متداول AddDbContext
و سپس روش جدید AddDbContextPool
بررسی و اجرا شدهاند. نتیجهی نهایی به صورت ذیل است:
همانطور که ملاحظه میکنید، در حالت ContextPooling، تعداد وهله سازیهای صورت گرفته به شدت کاهش یافتهاست و همچنین قابلیت پاسخدهی برنامه به علت کاهش سربار اتصال به بانک اطلاعاتی نیز حدود 55 درصد بهبود یافتهاست.
نحوهی معرفی DbContext pooling
اینبار بجای روش قبلی و استفاده از متد AddDbContext
services.AddDbContext<BloggingContext>( options => options.UseSqlServer(connectionString));
services.AddDbContextPool<BloggingContext>( options => options.UseSqlServer(connectionString));
محدودیتهای روش DbContext pooling
در حالت استفادهی از روش AddDbContextPool، دیگر متد OnConfiguring کلاس Context سفارشی شما فراخوانی نخواهد شد. بنابراین تمام تنظیمات ابتدایی برنامه را باید به همان کلاس آغازین برنامه منتقل کنید و کلاس Context، این تنظیمات را به صورت ذیل از طریق سازندهی آن دریافت میکند:
public class BloggingContext : DbContext { public BloggingContext(DbContextOptions<BloggingContext> options) : base(options){}
همچنین باید درنظر داشت که استفادهی مجدد از یک Context به معنای حفظ مقادیر فیلدهای private کلاس Context سفارشی شما نیز میشود. در اینجا پس از پایان هر درخواست، تنها وضعیت Context از دیدگاه EF به حالت اول بازگشت داده میشود؛ اما حالت شیء Context و تمام اطلاعات فیلدهای خصوصی آن در همان حالت قبلی (و همان وهلهی موجود پیشین و اصلی) رها میشوند. چون وهله سازی مجددی از آن صورت نخواهد گرفت.
یک مثال: بررسی بهبود کارآیی برنامه در حالت استفادهی از DbContext pooling
کدهای کامل این مثال را برای اجرا میتوانید از اینجا دریافت کنید: ContextPooling.zip
در اینجا یکبار حالت متداول AddDbContext
public static void RunWithoutContextPooling() { Console.WriteLine("\nRun Without ContextPooling"); var serviceProvider = new ServiceCollection() .AddEntityFrameworkSqlServer() .AddDbContext<BloggingContext>( c => c.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.ContextPooling;Trusted_Connection=True;ConnectRetryCount=0;")) .BuildServiceProvider(); new RunTests().Start(serviceProvider); }
public static void RunWithContextPooling() { Console.WriteLine("\nRun With ContextPooling"); var serviceProvider = new ServiceCollection() .AddEntityFrameworkSqlServer() .AddDbContextPool<BloggingContext>( c => c.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.ContextPooling;Trusted_Connection=True;ConnectRetryCount=0;"), poolSize: 16) .BuildServiceProvider(); new RunTests().Start(serviceProvider); }
Run Without ContextPooling [10:49:30.728] Context creations: 637 | Requests per second: 597 [10:49:31.746] Context creations: 1069 | Requests per second: 1050 [10:49:32.765] Context creations: 1088 | Requests per second: 1067 [10:49:33.784] Context creations: 1139 | Requests per second: 1119 [10:49:34.802] Context creations: 1138 | Requests per second: 1117 [10:49:35.831] Context creations: 1153 | Requests per second: 1120 [10:49:36.845] Context creations: 1126 | Requests per second: 1111 [10:49:37.873] Context creations: 1014 | Requests per second: 987 [10:49:38.898] Context creations: 1139 | Requests per second: 1111 [10:49:39.918] Context creations: 1086 | Requests per second: 1065 Total context creations: 10592 Requests per second: 1034 Run With ContextPooling [10:49:40.982] Context creations: 32 | Requests per second: 1388 [10:49:41.991] Context creations: 0 | Requests per second: 1691 [10:49:43.014] Context creations: 0 | Requests per second: 1684 [10:49:44.031] Context creations: 0 | Requests per second: 1702 [10:49:45.049] Context creations: 0 | Requests per second: 1694 [10:49:46.067] Context creations: 0 | Requests per second: 1401 [10:49:47.075] Context creations: 0 | Requests per second: 1510 [10:49:48.107] Context creations: 0 | Requests per second: 1669 [10:49:49.127] Context creations: 0 | Requests per second: 1679 [10:49:50.147] Context creations: 0 | Requests per second: 1688 Total context creations: 32 Requests per second: 1610