نظرات مطالب
خودمونیم! بد طراحی شده. از المان یک enum میشده/میشه مستقیما خارج از enum بدون ارجاعی به اون استفاده کرد؟! به این میگن بیش از حد دست و دلبازی و منشاء سردرگمی (که در نگارش 11 به اسم type-saftey بالاخره رفع و رجوعش کردن).
عبارت foreach در زبان #C، امکان پیمایش اعضای یک مجموعه را میسر میکند؛ اما نه هر مجموعهای. این مجموعهی خاص باید به این صورت تعریف شده باشد:
مثال 1: نوع <IEnumerator<T با حلقهی foreach سازگار نیست
قابلیت پیمایش توسط حلقهی foreach را ندارد. اگر در C# 8.0 این حلقه را بر روی آن اعمال کنیم، به خطای کامپایلر زیر میرسیم:
اما میتوان به صورت زیر در C# 9.0، این متد را به آن اضافه کرد:
اکنون حلقهی foreach را میتوان بر روی نوعهای <IEnumerator<T نیز بکار گرفت:
این نکته بر روی نمونهی async آن نیز قابل اعمال است که مثالی از آنرا در ادامه مشاهده میکنید:
مثال زیر را درنظر بگیرید:
در اینجا سعی کردهایم تا حلقهی foreach را بر روی یک tuple سه عضوی، اعمال کنیم. اما با خطای کامپایلر زیر مواجه میشویم:
برای رفع این خطا در C# 9.0 تنها کافی است متد الحاقی GetEnumerator مخصوص نوع آنرا طراحی و به برنامه اضافه کرد:
الف) <IEnumerable<T را پیاده سازی کرده باشد.
ب) و یا ... مهم نیست که این مجموعه حتما <IEnumerable<T را پیاده سازی کرده باشد. اگر این مجموعه به همراه یک متد عمومی خاص با نام GetEnumerator باشد که خروجی آن دارای خاصیت عمومی T Current است (یکی از اعضای اینترفیس <IEnumerable<T) و همچنین به همراه متد عمومی bool MoveNext نیز هست (یکی از اعضای اینترفیس IEnumerator)، قابلیت کار با حلقهی foreach را پیدا میکند و ... اکنون در C# 9.0 میتوان متد GetEnumerator را به صورت یک متد الحاقی، به هر نوع دلخواهی اعمال کرد! یعنی میتوان برای هر نوعی در صورت نیاز، یک GetEnumerator خاص را طراحی کرد که سبب به کار افتادن حلقهی foreach بر روی آن شود.
مثال 1: نوع <IEnumerator<T با حلقهی foreach سازگار نیست
نوع <IEnumerator<T به دلیل نداشتن متد عمومی GetEnumerator که ذکر شد:
public interface IEnumerator<out T> : IEnumerator, IDisposable { // // Summary: // Gets the element in the collection at the current position of the enumerator. // // Returns: // The element in the collection at the current position of the enumerator. T Current { get; } }
Error CS1579 foreach statement cannot operate on variables of type ‘IEnumerator’ because ‘IEnumerator’ does not contain a public instance or extension definition for ‘GetEnumerator’
static class Extensions { public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator; }
اکنون حلقهی foreach را میتوان بر روی نوعهای <IEnumerator<T نیز بکار گرفت:
class Program { void Main() { var enumerator = Enumerable.Range(0, 10).GetEnumerator(); foreach (var item in enumerator) { Console.WriteLine(item); } } }
این نکته بر روی نمونهی async آن نیز قابل اعمال است که مثالی از آنرا در ادامه مشاهده میکنید:
static class Extensions { public static IAsyncEnumerator<T> GetAsyncEnumerator<T>(this IAsyncEnumerator<T> enumerator) => enumerator; } class Program { static async Task Main() { var enumerator = GetAsyncEnumerator(); await foreach (var item in enumerator) { Console.WriteLine(item); } } static async IAsyncEnumerator<int> GetAsyncEnumerator() { yield return 0; await Task.Delay(1); yield return 1; } }
مثال 2: اضافه کردن پشتیبانی از حلقهی foreach بر روی نوعهای tuple
مثال زیر را درنظر بگیرید:
class Program { static void Main() { foreach (var item in (1, 2, 3)) { Console.WriteLine(item); } } }
foreach statement cannot operate on variables of type '(int, int, int)' because '(int, int, int)' does not contain a public instance or extension definition for 'GetEnumerator' [CS9Features]csharp(CS1579)
static class Extensions { public static IEnumerator<object> GetEnumerator<T1, T2, T3>(this ValueTuple<T1, T2, T3> tuple) { yield return tuple.Item1; yield return tuple.Item2; } }
نظرات مطالب
خواندنیهای 28 اردیبهشت
سلام،
- بله. این لیست هر جمعه بر اساس یافتههای جدید من به روز میشود.
- بله:
https://www.dntips.ir/2009/03/it.html
- بله. این لیست هر جمعه بر اساس یافتههای جدید من به روز میشود.
- بله:
https://www.dntips.ir/2009/03/it.html
نظرات مطالب
اشتباهات متداول برنامهنویسهای دات نت
در این رابطه
http://weblogcrawler.blogspot.com/2009/03/feed-in-poersian-bloggers.html
http://weblogcrawler.blogspot.com/2009/03/feed-in-poersian-bloggers.html
نظرات مطالب
Postable
نه با مطالب دیگری هم که ارسال کردید به همین صورت است برای مثال
http://yourite/2011/03/blog-post_12.html
http://yourite/2011/03/blog-post_12.html
یکی از نقشهای IISهای جدید (از نگارش 7 به بعد) که در ویندوز سرورهای قابل نصب است، نقش Performance است و ذیل آن دو نقش فشرده سازی استاتیک و پویا قابل انتخاب است. اگر این نقشها بر روی سرور نصب باشند، دیگر نیازی به استفاده از HTTP Moduleهای متداول فشرده سازی صفحات وب نیست. برای استفادهی از آن تنها کافی است کمی web.config را ویرایش کرد و ... گفته شدهاست که کار میکند! اما پس از اعمال تنظیمات، اگر به هدرهای خروجی Response صفحه در ابزارهای web developer مرورگرها دقت کنید، خبری از encoding جدیدی به نام gzip نیست (Content-Encoding: gzip) و به نظر اعمال نمیشود. در ادامه بررسی خواهیم کرد که چرا اینگونه است.
فعال سازی GZip توکار IIS
تنظیمات پیش فرض فعال سازی ماژول توکار GZip وب سرورهای جدید شامل دو مرحله است:
الف) تنظیمات سرور جهت فعال سازی فشرده سازی
بر روی ویندوزهای سرور، پس از مراجعه به Administrative Tools -> Server Manager و گشودن Roles آن، ذیل قسمت Web Server که در اینجا IIS است، نیاز است نقش جدیدی به نام Performance اضافه شود و مطابق تصویر، هر دو گزینهی فشرده سازی استاتیک و پویا انتخاب گردد.
بنابراین اولین قدم برای عیب یابی کار نکردن GZip توکار IIS، از این مرحله شروع میشود که آیا اصلا ماژول مربوطه نصب هست یا خیر؟
ب) تنظیمات برنامه جهت فعال سازی ماژول GZip
پس از اطمینان از نصب ماژول توکار فشرده سازی صفحات وب IIS در سمت تنظیمات سرور، اکنون باید چند سطر ذیل را به Web.Config برنامه اضافه کرد:
در اینجا تنظیمات مخصوص نحوهی فعال سازی فشرده سازی توکار صفحات پویا و فایلهای استاتیک را مشاهده میکنید. در این تنظیمات محل قرارگیری فایلهای موقتی فشرده شدهی توسط این ماژول و همچنین mime typeهای مدنظر جهت فشرده سازی، ذکر شدهاند. با این تنظیمات، تنها mime typeهایی که به صورت صریح ذکر شدهاند فشرده خواهند شد و از سایر mime types صرفنظر میشود.
این تنظیماتی است که در اکثر سایتها نیز یافت میشود. ذکر آنها اجباری است و پس از اعمال، اگر برنامه را اجرا کنید ... چیزی فشرده نمیشود! علت اصلی را باید در تنظیماتی یافت که مخصوص سرور است و در اینجا ذکر نشدهاند.
تنظیمات مخصوص آستانهی فشرده سازی صفحات
علت اصلی عدم مشاهدهی هدر gzip، در Response برنامه، به frequent hit threshold تنظیم شدهی در IIS بر میگردد. مقدار آن به 2 درخواست در طی 10 ثانیه تنظیم شدهاست. یعنی اگر به صفحهای در طی 10 ثانیه دو درخواست نرسد، فشرده نخواهد شد. این تنظیم را میتوان با مراجعهی به configuration editor نود اصلی سرور وب در IIS manager، ویرایش کرد:
برای نمونه در تصویر فوق، این آستانه به یک درخواست در طی 10 ساعت تنظیم شدهاست. این عدد سبب خواهد شد تا تمامی درخواستهای رسیده حتما فشرده سازی شوند.
این تنظیم معادل یک سطر ذیل در فایل web.config است. اما چون قسمت system.webServer/serverRuntime در تنظیمات سرور قفل شدهاست، هیچ تاثیری نخواهد داشت و حتما باید در سمت سرور و توسط IIS manager اعمال شود:
برای آزاد سازی این تنظیمات نیاز است دستور ذیل بر روی سرور اجرا شود. پس از آن کاربران برنامههای وب میتوانند از تنظیمات وب کانفیگ خاص خود استفاده کنند:
یک نکته
اگر از سرورهای پس از 2008 استفاده میکنید، گزینهی staticCompressionIgnoreHitFrequency نیز به تنظیمات serverRuntime اضافه شدهاست که با تنظیم آن به true، از این حد آستانه، برای فایلهای استاتیک صرفنظر خواهد شد.
تنظیمات مخصوص اندازهی فایلهایی که باید فشرده سازی شوند
تنها حد آستانهی درخواست صفحات وب نیست که بر روی فشرده سازی یا عدم آن ثاثیرگذار است. در اینجا میزان CPU Usage سیستم و یا حتی اندازهی Response خروجی نیز مهم هستند که نمونهای از تنظیمات آنرا در شکل ذیل مشاهده میکنید:
در اینجا با تنظیم minFileSizeForComp به 1024، اعلام شدهاست که حجمهایی کمتر از یک کیلوبایت، فشرده سازی نشوند (مقدار پیش فرض آن، بیش از این عدد است).
البته این عدد را به شکل زیر نیز میتوان به تنظیمات httpCompression وب کانفیگ اضافه کرد:
پس از اعمال این تنظیمات نیاز است یکبار IIS را نیز ری استارت کرد.
نتیجه گیری
اگر پس از فعال سازی GZip وب سرور، خروجی برنامه فشرده سازی نشد (Content-Encoding: gzip)، علت اینجا است که هنوز 2 درخواست مورد نیاز، در طی 10 ثانیه به سمت سرور ارسال نشدهاند و تنظیمات پیش فرض این ماژول، جهت حداقل مصرف CPU و فشار بر روی سرور است.
فعال سازی GZip توکار IIS
تنظیمات پیش فرض فعال سازی ماژول توکار GZip وب سرورهای جدید شامل دو مرحله است:
الف) تنظیمات سرور جهت فعال سازی فشرده سازی
بر روی ویندوزهای سرور، پس از مراجعه به Administrative Tools -> Server Manager و گشودن Roles آن، ذیل قسمت Web Server که در اینجا IIS است، نیاز است نقش جدیدی به نام Performance اضافه شود و مطابق تصویر، هر دو گزینهی فشرده سازی استاتیک و پویا انتخاب گردد.
بنابراین اولین قدم برای عیب یابی کار نکردن GZip توکار IIS، از این مرحله شروع میشود که آیا اصلا ماژول مربوطه نصب هست یا خیر؟
ب) تنظیمات برنامه جهت فعال سازی ماژول GZip
پس از اطمینان از نصب ماژول توکار فشرده سازی صفحات وب IIS در سمت تنظیمات سرور، اکنون باید چند سطر ذیل را به Web.Config برنامه اضافه کرد:
<system.webServer> <httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files"> <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" /> <dynamicTypes> <add mimeType="text/*" enabled="true" /> <add mimeType="message/*" enabled="true" /> <add mimeType="application/x-javascript" enabled="true" /> <add mimeType="application/javascript" enabled="true" /> <add mimeType="application/json" enabled="true" /> <add mimeType="application/json; charset=utf-8" enabled="true" /> <add mimeType="application/atom+xml" enabled="true" /> <add mimeType="application/xaml+xml" enabled="true" /> <add mimeType="*/*" enabled="false" /> </dynamicTypes> <staticTypes> <add mimeType="text/*" enabled="true" /> <add mimeType="message/*" enabled="true" /> <add mimeType="application/x-javascript" enabled="true" /> <add mimeType="application/javascript" enabled="true" /> <add mimeType="application/json" enabled="true" /> <add mimeType="application/json; charset=utf-8" enabled="true" /> <add mimeType="application/atom+xml" enabled="true" /> <add mimeType="application/xaml+xml" enabled="true" /> <add mimeType="*/*" enabled="false" /> </staticTypes> </httpCompression> <urlCompression doStaticCompression="true" doDynamicCompression="true" /> </system.webServer>
این تنظیماتی است که در اکثر سایتها نیز یافت میشود. ذکر آنها اجباری است و پس از اعمال، اگر برنامه را اجرا کنید ... چیزی فشرده نمیشود! علت اصلی را باید در تنظیماتی یافت که مخصوص سرور است و در اینجا ذکر نشدهاند.
تنظیمات مخصوص آستانهی فشرده سازی صفحات
علت اصلی عدم مشاهدهی هدر gzip، در Response برنامه، به frequent hit threshold تنظیم شدهی در IIS بر میگردد. مقدار آن به 2 درخواست در طی 10 ثانیه تنظیم شدهاست. یعنی اگر به صفحهای در طی 10 ثانیه دو درخواست نرسد، فشرده نخواهد شد. این تنظیم را میتوان با مراجعهی به configuration editor نود اصلی سرور وب در IIS manager، ویرایش کرد:
برای نمونه در تصویر فوق، این آستانه به یک درخواست در طی 10 ساعت تنظیم شدهاست. این عدد سبب خواهد شد تا تمامی درخواستهای رسیده حتما فشرده سازی شوند.
این تنظیم معادل یک سطر ذیل در فایل web.config است. اما چون قسمت system.webServer/serverRuntime در تنظیمات سرور قفل شدهاست، هیچ تاثیری نخواهد داشت و حتما باید در سمت سرور و توسط IIS manager اعمال شود:
<system.webServer> <serverRuntime frequentHitThreshold="1" frequentHitTimePeriod="10:00:00" /> </system.webServer>
C:\Windows\System32\inetsrv\appcmd.exe unlock config /section:system.webServer/serverRuntime
یک نکته
اگر از سرورهای پس از 2008 استفاده میکنید، گزینهی staticCompressionIgnoreHitFrequency نیز به تنظیمات serverRuntime اضافه شدهاست که با تنظیم آن به true، از این حد آستانه، برای فایلهای استاتیک صرفنظر خواهد شد.
تنظیمات مخصوص اندازهی فایلهایی که باید فشرده سازی شوند
تنها حد آستانهی درخواست صفحات وب نیست که بر روی فشرده سازی یا عدم آن ثاثیرگذار است. در اینجا میزان CPU Usage سیستم و یا حتی اندازهی Response خروجی نیز مهم هستند که نمونهای از تنظیمات آنرا در شکل ذیل مشاهده میکنید:
در اینجا با تنظیم minFileSizeForComp به 1024، اعلام شدهاست که حجمهایی کمتر از یک کیلوبایت، فشرده سازی نشوند (مقدار پیش فرض آن، بیش از این عدد است).
البته این عدد را به شکل زیر نیز میتوان به تنظیمات httpCompression وب کانفیگ اضافه کرد:
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files" minFileSizeForComp="1024">
پس از اعمال این تنظیمات نیاز است یکبار IIS را نیز ری استارت کرد.
نتیجه گیری
اگر پس از فعال سازی GZip وب سرور، خروجی برنامه فشرده سازی نشد (Content-Encoding: gzip)، علت اینجا است که هنوز 2 درخواست مورد نیاز، در طی 10 ثانیه به سمت سرور ارسال نشدهاند و تنظیمات پیش فرض این ماژول، جهت حداقل مصرف CPU و فشار بر روی سرور است.
استفاده از DDL Trigger
امکان ایجاد Trigger برای عملیات (DDL(Data Definition Language از SQL Server 2005 فراهم گردید. عملیاتی مانند ایجاد یک جدول جدید در بانک اطلاعاتی، اضافه شدن یک Login جدید و یا ایجاد یک بانک اطلاعاتی جدید را به وسیله این نوع Triggerها میتوان کنترل نمود. در حقیقت DDL Trigger به شما اجازه میدهد که از تاثیر تعدادی از دستورات DDL جلوگیری کنید. بدین ترتیب که تقریباً هر دستور DDL به طور خودکار، تراکنشی (Transactional) اجرا میشود . میتوان با دستور ROLLBACK TRANSACTION اجرای دستور DDL را لغو نمود. توجه شود همه دستورات DDL به صورت تراکنشی اجرا نمیشوند، به عنوان مثال دستور ALTER DATABASE ممکن است Database را تغییر دهد. در این صورت ساختار فایلی Database را تغییر میدهد، از آنجائی که سیستم عامل ویندوز به صورت تراکنشی عمل نمیکند بنابراین شما نمیتوانید این عمل فایل سیستمی را لغو نمائید. به هر حال شما میتوانید Trigger را با ALTER DATABASE فعال (fire) کنید برای عملیات Auditing، ولی نمیتوان از انجام عمل ALTER DATABASE جلوگیری کرد.برای نمونه میخواهیم از حذف و یا تغییر جداول یک بانک اطلاعاتی که به صورت عملیاتی در حال سرویس دهی است جلوگیری کنیم، برای اینکار از دستورهای زیر استفاده میکنیم:
create trigger Prevent_AlterDrop on database for drop_table, alter_table as print 'table can not be dropped or altered' rollback transaction
1- معرفی تابع ()EVENTDATA
این تابع، یک تابع سیستمی مهم است که در DDL Trigger استفاده میشود. در حالیکه DDL Trigger در هر سطحی فعال (fire) شود تابع سیستمی ()EVENTDATA فراخوانی (raise) میشود. خروجی تابع در قالب XML است. میتوان اطلاعات را از تابع EVENTDATA دریافت کرد و آنها را در یک جدول با فیلدی از جنس XML و یا با استفاده از XPath Query ثبت کرد (Logging). عناصر کلیدی (Key Elements) تابع EVENTDATA به شرح زیر است:• EventType: نوع رویدادی که باعث فراخوانی Trigger شده است.
• PostTime: زمانی که رویداد رخ میدهد.
• SPID :SPID کاربری که باعث ایجاد رویداد شده است.
• ServerName: نام SQL Instance که رویداد در آن رخ داده است.
• LoginName: نام Login که عمل مربوط به وقوع رویداد را اجرا میکند.
• UserName: نام User که عمل مربوط به وقوع رویداد را اجرا میکند.
• DatabaseName: نام Database که رویداد در آن رخ میدهد.
• ObjectType: نوع Object که اصلاح، حذف و یا ایجاد شده است.
• ObjectName: نام Object که اصلاح، حذف و یا ایجاد شده است.
• TSQLCommand: دستور T-SQL که اجرا شده و باعث اجرا شدن Trigger شده است.
2- بررسی یک سناریو نمونه
برای نمونه در دستورات زیر جدولی با نام ddl_log
CREATE TABLE ddl_log ( EventType nvarchar(100), PostTime datetime, SPID nvarchar(100), ServerName nvarchar(100), LoginName nvarchar(100), UserName nvarchar(100), DatabaseName nvarchar(100), ObjectName nvarchar(100), ObjectType nvarchar(100), DefaultSchema nvarchar(100), [SID] nvarchar(100), TSQLCommand nvarchar(2000));
CREATE TRIGGER [Log] ON DATABASE FOR DDL_DATABASE_LEVEL_EVENTS AS DECLARE @data XML SET @data = EVENTDATA() INSERT INTO ddl_log VALUES ( @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime'), @data.value('(/EVENT_INSTANCE/SPID)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/ServerName)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/UserName)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/ObjectType)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/DefaultSchema)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/SID)[1]', 'nvarchar(100)'), @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)'));
3- ملاحظات
در صورت فعال شدن Trigger میتوان برخی موارد مانند محدودیت زمانی، کاربر اجرا کننده و ... را اضافه نمود. برای مثال در دستور زیر اجازه تغییرات در این زمان ( بین 7:00 A.M. تا .8:00 P.M ) امکان پذیر نیست و در صورت اقدام پیغام خطا دریافت میکنید و دستورات Create لغو خواهند شد و اگر خارج از زمان فوق دستورات DDL را اجرا کنید دستورات به طور موفقیت آمیز اجرا میشود و البته تغییرات نیز Log میشوند.
پس از Overrdie کردن میتوانید مجدداً Trigger را فعال کنید:
4- معرفی DDL Event Groups:
برای مشاهده جزئیات بیشتر میتوانید به این لینک مراجعه کنید.
Server Level
DDL_SERVER_LEVEL_EVENTS
DDL_LINKED_SERVER_EVENTS
DDL_LINKED_SERVER_LOGIN_EVENTS
DDL_REMOTE_SERVER_EVENTS
DDL_EXTENDED_PROCEDURE_EVENTS
DDL_MESSAGE_EVENTS
DDL_ENDPOINT_EVENTS
DDL_SERVER_SECURITY_EVENTS
DDL_LOGIN_EVENTS
DDL_GDR_SERVER_EVENTS
DDL_AUTHORIZATION_SERVER_EVENT Database Level
Database Level
DDL_DATABASE_LEVEL_EVENTSDDL_TABLE_VIEW_EVENTS
DDL_TABLE-EVENTS
DDL_VIEW_EVENTS
DDL_INDEX_EVENTS
DDL_STATISTICS_EVENTS
DDL_DATABASE_SECURITY_EVENTS
DDL_CERTIFICATE_EVENTS
DDL_USER_EVENTS
DDL_ROLE_EVENTS
DDL_APPLICATION_ROLE_EVENTS
DDL_SCHEMA_EVENTS
DDL_GDR_DATABASE_EVENTS
DDL_AUTHORIZATION_DATABASE_EVENTS
DDL_FUNCTION_EVENTS
DDL_PROCEDUER_EVENTS
DDL_TRIGGER_EVENTS
DDL_PARTITION_EVENTS
DDL_PARTITION_FUNCTION_EVENTS
DDL_PARTITION_SCHEME_EVENTS
DDL_SSB_EVENTS
DDL_MESSAGE_TYPE_EVENTS
DDL_CONTRACT_EVENTS
DDL_QUEUE_EVENTS
DDL_SERVER_EVENTS
DDL_ROUTE_EVENTS
DDL_REMOTE_SERVICE_BINDING_EVENTS
DDL_XML_SCHEMA_COLEECTION_EVENTS
DDL_FULLTEXT_CATALOG_EVENTS
DDL_DEFAULT_EVENTS
DDL_EXTENDED_PROPERTY_EVENTS
DDL_PLAN_GUIDE_EVENTS
DDL_RULE_EVENTS
DDL_SYNONYM_EVENTS
DDL_EVENT_NOTIFICATION_EVENTS
DDL_ASSEMBLY_EVENTS
DDL_TYPE_EVENTS
یکی از نیازهایی که در حین کار با دیتابیسها احساس میشود، دریافت
اطلاعات ورودی از فرمتهای دیگر و یا تبدیل
دیتای موجود به قالبهای دیگر است. به عنوان مثال خروجی دیتا را
به CSV و یا اطلاعات CSV را در دیتابیس وارد کنیم.
در ادامهی کار با ابزارهای پشتیبان گیری که داخل شاخه Bin قرار داشتند، ابزارهای دیگری را معرفی میکنیم.
MongoExport از اطلاعات داخل دیتابیس شما خروجی گرفته و آنرا به قالب مورد نظر بر میگرداند. تعدادی از پارامترهای آن به شرح زیر است:
دستور بالا نام و isbn کتابها را در قالب فایل csv ذخیره میکند.
توجه: نام فیلدها، CaseSensitive بوده و در غیر اینصورت، فیلد مورد نظر شامل ستونی خالی خواهد بود.
MongoImport هم برای ورود دادهها به کار میرود. پارامترهای این دستور همانند بالا است، ولی با چند پارامتر مهم دیگر که در پایین ذکر میشود:
کد بالا، فایل قبلی را به داخل فایل اضافه میکند.
در ادامهی کار با ابزارهای پشتیبان گیری که داخل شاخه Bin قرار داشتند، ابزارهای دیگری را معرفی میکنیم.
MongoExport از اطلاعات داخل دیتابیس شما خروجی گرفته و آنرا به قالب مورد نظر بر میگرداند. تعدادی از پارامترهای آن به شرح زیر است:
نام پارامتر | شرح کارکرد |
c- یا collection-- | میتواند خروجی را به یک کالکشن خاص محدود کند. |
d- یا db-- | از دیتابیسی مشخص استفاده کند. |
u- یا username- | نام کاربری سرور |
p- یا password-- | کلمه عبور سرور |
dbpath-- | مسیر پوشهای را که دیتاها داخل آن است، دریافت میکند و به جای ایجاد یک Instance مستقیم، خروجی را ارائه میکند. توجه : در این حالت پوشه به طور کامل قفل خواهد شد و سرور نباید در حالت اجرا قرار گرفته باشد. |
DirectoryPerDb-- | در صورتیکه هر دیتابیسی دارای محل جداگانهای برای خروجی باشد. |
o- یا out-- | محل ذخیره خروجی را مشخص میکند. |
f- یا field-- | نام فیلدهایی که قرار است در خروجی ظاهر شوند. به شکل زیر نوشته میشود: field Title,ISBN-- |
fieldfile-- | معرفی نام فیلدها در یک فایل جداگانه. نام هر فیلد در یک خط باید قرار بگیرد. Title ISBN |
q- یا query-- | خروجی به شکل کوئری و جیسن در قالب رشته |
csv-- | خروجی csv به جای جیسن |
D:\Program Files\MongoDB\Server\3.4\bin>mongoexport -d publisher -c books -f Title,ISBN --csv -o D:\temp\books.csv 2017-03-04T22:50:20.671+0330 csv flag is deprecated; please use --type=csv instead 2017-03-04T22:50:20.673+0330 connected to: localhost 2017-03-04T22:50:20.673+0330 exported 7 records
توجه: نام فیلدها، CaseSensitive بوده و در غیر اینصورت، فیلد مورد نظر شامل ستونی خالی خواهد بود.
MongoImport هم برای ورود دادهها به کار میرود. پارامترهای این دستور همانند بالا است، ولی با چند پارامتر مهم دیگر که در پایین ذکر میشود:
پارامتر | شرح کارکرد |
ignoreBlanks | مقادیر خالی ندیده گرفته میشوند. |
type-- | نوع فایل ورودی چیست؟ json,tsv,csv |
upset | درج مقادیری که از قبل موجود هستند. |
upsertFields | همانند بالا فقط برای فیلدهایی که ذکر شدهاست. |
stopOnError | با برخورد به اولین خطا، کار ورود را نادیده بگیر. |
D:\Program Files\MongoDB\Server\3.4\bin>mongoimport -d publisher -c books -f Title,ISBN --type csv D:\temp\books.csv 2017-03-04T23:05:50.588+0330 connected to: localhost 2017-03-04T23:05:50.591+0330 imported 8 documents
کد بالا، فایل قبلی را به داخل فایل اضافه میکند.
هدف از توابع خطی(Inline)
استفاده از توابع، مقداری بر زمان اجرای برنامه میافزاید؛ هرچند که این زمان بسیار کم و در حد میلی ثانیه است، اما باری را بر روی برنامه قرار میدهد و علت این تاخیر زمانی این است که در فراخوانی و اعلان توابع، کامپایلر یک کپی از تابع مورد نظر را در حافظه قرار میدهد و در فراخوانی تابع، به آدرس مذکور مراجعه میکند و در عین حال آدرس موقعیت توقف دستورات در تابع main را نیز ذخیره میکند تا پس از پایان تابع، به آدرس قبل برگردد و ادامهی دستورات را اجرا کند. در نتیجه این آدرس دهیها و نقل و انتقالات بین آنها بار زمانی را در برنامه ایجاد میکند که در صورت زیاد بودن توابع در برنامه و تعداد فراخوانیهای لازم، زمان قابل توجهی خواهد شد.
یکی از تکنیکهای بهینه که برای کاهش زمان اجرای برنامه توسط کامپایلرها استفاده میشود استفاده از توابع خطی (inline) است. این امکان در زبان C با عنوان توابع ماکرو(Macro function) و در ++C با عنوان توابع خطی (inline function) وجود دارد.
در واقع توابع خطی به کامپایلر پیشنهاد میدهند، زمانی که سربار فراخوانی تابع بیشتر از سربار بدنه خود متد باشد، برای کاهش هزینه و زمان اجرای برنامه از تابع به صورت خطی استفاده کند و یک کپی از بندهی تابع را در قسمتی که تابع ما فراخوانی شده است، قرار دهد که مورد آدرس دهی از میان خواهد رفت!
نمونه ای از پیاده سازی این تکنیک در زبان ++C :
inline type name(parameters) { ... }
بررسی متدهای خطی در سی شارپ
به مثال زیر توجه کنید:
قسمتهای getter و setter مربوط به پراپرتیها سربار اضافی بر کلاس Vector میافزایند. این موضوع شاید آنچنان مسئلهی مهمی نباشد. ولی فرض کنید این پراپرتیها به شکل زیر داخل حلقهای طولانی قرار گیرند. اگر با استفاده از یک پروفایلر زمان اجرای برنامه را زیر نظر بگیرید، خواهید دید که بیش از 90 درصد آن صرف فراخوانیهای متدهای بخشهای get , set پراپرتیها است. برای این منظور باید مطمئن شویم که فراخوانی این متدها، به صورت خطی صورت میگیرد!
public class Vector { public double X { get; set; } public double Y { get; set; } public double Z { get; set; } // ... }
برای این منظور آزمایشی را انجام میدهیم. فرض کنید کلاسی را به شکل زیر داشته باشیم:
public class MyClass { public int A { get; set; } public int C; }
static void Main() { MyClass target = new MyClass(); int a = target.A; Console.WriteLine("A = {0}", a); int c = target.C; Console.WriteLine("C = {0}", c); }
int a = target.A; 0000003e mov ecx,edi 00000040 cmp dword ptr [ecx],ecx 00000042 call dword ptr ds:[05FA29A8h] 00000048 mov esi,eax 0000004a mov dword ptr [esp+4],esi int c = target.C; 00000098 mov edi,dword ptr [edi+4] MyClass.get_A() looks like this: 00000000 push esi 00000001 mov esi,ecx 00000003 cmp dword ptr ds:[03B701DCh],0 0000000a je 00000011 0000000c call 76BA6BA7 00000011 mov eax,dword ptr [esi+0Ch] 00000014 pop esi 00000015 ret
چه اتفاقی افتاده است؟
کامپایلر سی شارپ در زمان کامپایل، کدهای برنامه را به کدهای IL تبدیل میکند و JITکامپایلر، این کدهای IL را گرفته و کد سادهی ماشین را تولید میکند. لذا به دلیل اینکه JIT با معماری پردازنده آشنایی کافی دارد، مسئولیت تصمیم گیری اینکه کدام متد به صورت خطی فراخوانی شود برعهدهی آن است. در واقع این JIT است که تشخیص میدهد که آیا فراخونی متد به صورت خطی مناسب است یا نه و به صورت یک معاوضه کار بین خط لوله دستورالعملها و کش است.
اگر شما برنامهی خود را با (F5) و همگام با دیباگ اجرا کنید، تمام بهینه سازیهای JIT که Inline Method هم یکی از آنهاست، از کار خواهند افتاد. برای مشاهدهی کد بهینه شده باید با بدون دیباگ (CTRL+F5) برنامه خود را اجرا کنید که در آن صورت مشاهده خواهید کرد، متد getter مربوط به پراپرتی A به صورت خطی استفاده شده است.
int a = target.A; 00000024 mov ebx,dword ptr [edi+0Ch]
JIT محدودیت هایی برای فراخونی به صورت خطی متدها دارد :
- متد هایی که حجم کد IL آنها بیشتر از 32 بایت است.
- متدهای بازگشتی.
- متدهایی که با اتریبیوت MethodImpl علامتگذاری شدند و MethodImplOptions.NoInlining اعمال شده بر آن
- متدهای virtual
- متدهایی که دارای کد مدیریت خطا هستند
- Methods that take a large value type as a parameter
- Methods with complicated flowgraphs
برای اینکه در سی شارپ به کامپایلر اعلام کنیم تا متد مورد نظر به صورت خطی مورد استفاده قرار گیرد، در دات نت 4.5 توسط اتریبیوت MethodImpl و اعمال MethodImplOptions.AggressiveInlining که یک نوع شمارشی است میتوان این کار را انجام داد. مثال:
using System; using System.Diagnostics; using System.Runtime.CompilerServices; class Program { const int _max = 10000000; static void Main() { // ... Compile the methods. Method1(); Method2(); int sum = 0; var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { sum += Method1(); } s1.Stop(); var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { sum += Method2(); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.Read(); } static int Method1() { // ... No inlining suggestion. return "one".Length + "two".Length + "three".Length + "four".Length + "five".Length + "six".Length + "seven".Length + "eight".Length + "nine".Length + "ten".Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] static int Method2() { // ... Aggressive inlining. return "one".Length + "two".Length + "three".Length + "four".Length + "five".Length + "six".Length + "seven".Length + "eight".Length + "nine".Length + "ten".Length; } } Output 7.34 ns No options 0.32 ns MethodImplOptions.AggressiveInlining
مطالعه بیشتر: