عنوان:

‫سرعت ایجاد اشیاء CLR


نویسنده: وحید نصیری
تاریخ: ۱۳۹۰/۰۳/۲۲ ۱۱:۲۷:۰۰
آدرس: www.dntips.ir

به نظر شما چه تعداد شیء CLR را می‌توان در یک ثانیه ایجاد کرد؟
برنامه کنسول زیر دو نسخه معمولی و نسخه پردازش موازی یک آزمایش ساده را برای اندازه گیری این مطلب ارائه می‌دهد:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectInitSpeedTest
{
class Program
{
//Note: don't forget to build it in Release mode.
static void Main()
{
normalSpeedTest();
parallelSpeedTest();

Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Press a key ...");
Console.ReadKey();
}

private static void parallelSpeedTest()
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("parallelSpeedTest");

long totalObjectsCreated = 0;
long totalElapsedTime = 0;

var tasks = new List<Task>();
var processorCount = Environment.ProcessorCount;

Console.WriteLine("Running on {0} cores", processorCount);

for (var t = 0; t < processorCount; t++)
{
tasks.Add(Task.Factory.StartNew(
() =>
{
const int reps = 1000000000;
var sp = Stopwatch.StartNew();
for (var j = 0; j < reps; ++j)
{
new object();
}
sp.Stop();

Interlocked.Add(ref totalObjectsCreated, reps);
Interlocked.Add(ref totalElapsedTime, sp.ElapsedMilliseconds);
}
));
}

// let's complete all the tasks
Task.WaitAll(tasks.ToArray());

Console.WriteLine("Created {0:N} objects in 1 sec\n", (totalObjectsCreated / (totalElapsedTime / processorCount)) * 1000);
}

private static void normalSpeedTest()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("normalSpeedTest");

const int reps = 1000000000;
var sp = Stopwatch.StartNew();
sp.Start();
for (var j = 0; j < reps; ++j)
{
new object();
}
sp.Stop();

Console.WriteLine("Created {0:N} objects in 1 sec\n", (reps / sp.ElapsedMilliseconds) * 1000);
}
}
}

هنگام اجرای برنامه فراموش نکنید که حالت Build را بر روی Release قرار دهید.



نظرات

  • مهمان در ۱۳۹۰/۰۳/۲۲ ۱۳:۲۴:۳۹
    حالا چه نتیجه ای باید گرفت ؟!؟
    http://img.288.ir/images/objectinitspeedtest.png
  • مهمان در ۱۳۹۰/۰۳/۲۲ ۱۳:۳۷:۵۹
    http://img.288.ir/images/objectinitspeedtest2.png
  • وحید نصیری در ۱۳۹۰/۰۳/۲۲ ۱۴:۰۹:۰۶
    wow! این 32 هسته رو از کجا آوردید؟!
  • مهمان در ۱۳۹۰/۰۳/۲۲ ۱۴:۵۶:۳۱
    int processorCount = 32
  • مهمان در ۱۳۹۰/۰۳/۲۲ ۱۵:۲۰:۴۰
    مسئله اینجاس که با چهار برابر کردن مقداز processorCount واقعی نتیجه هم چهار برابر بهتر شده !
    (ولی کردم 64 دیگه نتیجه زیاد با 32 تغییری نکرد.)
  • مهمان در ۱۳۹۰/۰۳/۲۳ ۱۸:۳۰:۱۹
    من که نفهمیدم چرا با تغییر processorcount به 32 زمان کاهش پیدا کرد!!!
    اگه کسی میدونه بگه!!!
  • وحید نصیری در ۱۳۹۰/۰۳/۲۳ ۲۱:۴۹:۱۱
    نسخه پردازش موازی فوق به صورت پیش فرض بر اساس تعداد هسته‌های CPU تنظیم شده یعنی تصور کنید که روی هر هسته واقعا نسخه‌های normalSpeedTest به موازات هم در حال اجرا هستند. اگر 8 هسته باشد، 8 tasks خواهیم داشت.
    زمانیکه دستی تعداد هسته رو تنظیم کنید (بیشتر از تعداد واقعی هسته‌ها البته)، به همان نسخه‌ی threading سابق بر می‌گردیم یعنی اینبار task های اضافه شده بر اساس زمان آزاد پردازشی هسته‌ها، بین آن‌ها مرتبا سوئیچ خواهند شد و هر کدام که زودتر پایان یابد زمان پردازشی بیشتری را در اختیار مابقی تردهای ایجاد شده قرار می‌دهد. بدیهی است افزایش این عدد زمانیکه CPU به حد اشباع رسیده است (احتمالا شاید بوی سوختن آن به مشام رسیده باشد ...!)، تاثیر آنچنانی نخواهد داشت. علت اینکه عموما از تعداد هسته برای ایجاد parallel tasks استفاده می‌کنند هم همین مورد است. چون فقط برنامه شما نیست که قرار است از تمام توانایی‌های CPU استفاده کند.
  • وحید نصیری در ۱۳۹۰/۰۳/۲۳ ۲۲:۰۴:۱۷
    یک مطلب دیگر رو هم اضافه کنم. ThreadPool در دات نت 4 به 64 logical processors محدود شده. به عبارتی مثلا حین استفاده از Parallel.For/ForEach این محدودیت وجود دارد و پس از آزاد شدن یک task ، task بعدی (پس از 64 البته) وارد عمل خواهد شد و همینطور الی آخر
    +
    ویندوز سرور 2008 نگارش R2 فقط تا 256 logical processors رو پشتیبانی می‌کنه.
  • وحید نصیری در ۱۳۹۰/۰۳/۳۰ ۰۱:۱۲:۵۵
  • مهمان در ۱۳۹۰/۰۴/۰۳ ۱۴:۱۳:۵۶
    ظاهرا پردازنده‌های نسل i مثل i3، i5 و i7 دارای مکانیزم موازی سازی متفاوتی هستند که در این موارد تاثیر زیادی دارند برای مثال از یک پردازنده یک هسته‌ای نسل i می‌توان توان دو هسته‌ای گرفت به شرط دادن توان الکتریکی کافی به پردازنده. به علاوه بسیاری از سخت افزارهای جدید از Overclocking به صورت پویا پشتیبانی می‌کنند و ریختن بار زیادتر بر روی CPU جواب بهتری می‌دهد. غیر از Overclocking وقتی از CPU های مدرن کمتر از حد توانشان استفاده شود بخش‌هایی از خودشان را موقتاً غیر فعال می‌کنند تا از مصرف برق بکاهند وقتی بار CPU زیاد شود این بخش‌های خاموش، روشن شده و قدرت CPU بیشتر خواهد شد.

    شبیه همین مکانیزم در صورتی که سخت‌افزار مدرن باشد، درباره RAM نیز اتفاق می‌افتد. فکر می‌کنم به همین دلیل ریختن بار بیشتر بر CPU نتایجی دارد که گاهی عجیب به نظر می‌رسد.