Parallel سازي براي دات نت 2
۱۳۸۹/۰۷/۱۶ ۱۳:۴۲ منتشر شده در تاریخ : ۱۳۸۹/۰۷/۱۶ دسته بندی : آموزشی ، برنامه نویسی ، معرفی ، dotNET Framework ، Parallel Extension 1
برای حل این محدودیت می توان از روش های جایگزین استفاده کرد. گرچه این روشها باز هم به پای امکانات مهیا شده در دات نت 4 نمی رسد ولی باز هم بسیار راه گشا هستند. برای روش جایگزین می توان هم مستقیما از Thread ها استفاده کرد و هم از ThreadPool که کنترل thread ها را خودکار انجام می ده. البته این دو روش تفاوت فاحشی با هم دارند. تفاوت روش استفاده مستقیم از thread با threadpool عدم وابستگی به تعداد هسته cpu ها است، بدین معنا که در آن تقریبا همه آیتمها را به یکباره مورد پردازش قرار خواهند گرفت(البته به تعداد تعیین شده). اما threadpool همانند دات نت 4 عمل کرده و متدهای در حال اجرا و همزمان را به تعداد هسته cpu محدود می کند (با اندکی تفاوت). ابتدا متدی که مستقیما با thread ها کار می کند را معرفی می کنم و سپس روش threadpool را معرفی خواهم کرد.
با استفاده تابع زیر که تهیه کردم این امکان فراهم می آید که لیستی از آیتم ها را برای پردازش توسط یک متد یا رویه به طور همزمان پردازش نمایید. متد WorkAsParallel که در پایین ملاحظه می کنید دو ورودی می گیرد که ورودی اول لیستی جنریک از آیتم ها است و ورودی دوم متد پردازشگر مورد نظر که بر روی تک تک آیتم ها اجرا شده و عمل مورد تان را انجام می دهد.
public static void WorkAsParallel<T>(IList<T> itemsList, ParameterizedThreadStart itemDoWork) { // the maximum number of active threads const int maxThreads = 10; List<Thread> workers = new List<Thread>(); if (itemsList.Count > maxThreads) { int currentItem = 0; for (int i = 0; i < maxThreads; i++) { T item = itemsList[i]; try { Thread worker = new Thread(itemDoWork); worker.IsBackground = true; worker.Name = item.ToString(); workers.Add(worker); // item index currentItem++; // start the thread worker.Start(item); } catch { // ignore any exception } } // A little break in current thread Thread.Sleep(5); do { // start waiting for (int i = workers.Count - 1; i >= 0; i--) { Thread worker = workers[i]; if ((worker.ThreadState | ThreadState.Stopped) == ThreadState.Stopped) { workers.RemoveAt(i); // thread finished! run next irem if it is there if (currentItem <= itemsList.Count - 1) { T item = itemsList[currentItem]; worker = new Thread(itemDoWork); worker.IsBackground = true; worker.Name = item.ToString(); workers.Add(worker); // increase the item index currentItem++; // start the thread worker.Start(item); } } } // a little break Thread.Sleep(5); } while (itemsList.Count > currentItem); // now all the list items are in progress // start waiting for them to be done foreach (Thread worker in workers) { // just wait for it // an infinity wait! worker.Join(); } } else { // all items are starting in threads foreach (T item in itemsList) { try { Thread worker = new Thread(itemDoWork); worker.IsBackground = true; worker.Name = item.ToString(); workers.Add(worker); // start the thread worker.Start(item); } catch { // ignore any exception } } // A little break in current thread Thread.Sleep(5); // start waiting for them to be done foreach (Thread worker in workers) { // just wait for it // an infinity wait! worker.Join(); } } }
به طور پیش فرض تعداد thread فعال 10 در نظر گرفته شده است (توسط ثابت maxThreads که قابل افزایش است) بدین معنا که در صورتی تعداد آیتمهای لیست شما بیش از 10 تا باشد ابتدا فقط 10 آیتم ابتدایی اجرا خواهند شد و تنها پس از پایان هر thread آیتم بعدی مورد پردازش قرار خواهد گرفت. این محدودیت به خاطر جلوگیری از وارد شدن فشار بیش از حد به سیستم در نظر گرفته شده و در صورت صلاحدید شما قابل افزایش است.
- روش استفاده از WorkAsParallel
در مثال زیر یک لیست از DateTime با تاخیر زمانی 1 ثانیه چاپ می شود تا همزانی اجرا هم مشخص شود.
public void TestWorkAsParallel() { List<DateTime> theList = new List<DateTime>(); theList.Add(DateTime.Now.AddDays(1)); theList.Add(DateTime.Now.AddDays(2)); theList.Add(DateTime.Now.AddDays(3)); ParallelWorks.WorkAsParallel(theList, x => { DateTime item = (DateTime)x; Console.Write(item); Thread.Sleep(1000); }); }
و برای استفاده در VS 2005 که با کامپایلر CCS2 کار می کنه مثال مذبور رو به این تغییر بدید:
ParallelWorks.WorkAsParallel(theList, delegate(object x) { DateTime item = (DateTime) x; Console.Write(item); Thread.Sleep(1000); });
- استفاده از ThreadPool
متد مورد نظر من در این پست از وبلاگ معرفی شده است. این متد لیستی از متد های قابل اجرا را دریافت کرده و به صورت همزمان اجرا می کند.
public class ParallelProcessor { public delegate void Method(); /// <summary> /// Executes a set of methods in parallel and returns the results /// from each in an array when all threads have completed. The methods /// must take no parameters and have no return value. /// </summary> /// <param name="m"></param> /// <returns></returns> public static void ExecuteParallel(params Method[] methods) { // Initialize the reset events to keep track of completed threads ManualResetEvent[] resetEvents = new ManualResetEvent[methods.Length]; // Launch each method in it's own thread for (int i = 0; i < methods.Length; i++) { resetEvents[i] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(new WaitCallback((object index) => { int methodIndex = (int)index; // Execute the method methods[methodIndex](); // Tell the calling thread that we're done resetEvents[methodIndex].Set(); }), i); } // Wait for all threads to execute WaitHandle.WaitAll(resetEvents); } }
روش استفاده آن هم همانطور که در آن پست ذکر شده آسان است.
ParallelProcessor.ExecuteParallel(() => { Console.WriteLine("The long task 1"); Thread.Sleep(500); }, () => { Console.WriteLine("The long task 2"); Thread.Sleep(500); }, () => { Console.WriteLine("The long task 3"); Thread.Sleep(500); });
و برای VS2005 از این روش فراخوانی استفاده کنید:
ParallelProcessor.Method[] methods = new ParallelProcessor.Method[3]; methods[0] = delegate{ Console.WriteLine("The long task 1"); Thread.Sleep(500); }; methods[1] = delegate{ Console.WriteLine("The long task 1"); Thread.Sleep(500); }; methods[2] = delegate{ Console.WriteLine("The long task 1"); Thread.Sleep(500); }; ParallelProcessor.ExecuteParallel(methods);
- مقایسه WorkAsParallel و ParallelProcessor در عمل
مسلما مقایسه این دو روش زیاد صحیح نخواهد بود. این به علت متفاوت بودن شیوه اجرای این دو روش است. به هرحال جهت نمایش این تفاوت مثال زیر را اجرا می کنیم:
static void Main(string[] args) { Console.WriteLine("Parallels for .NET 2, salarblog.wordpress.com"); // The list List<int> taskList = new List<int>() { 1, 2, 3, 4, 5, 6 }; var pwatch = Stopwatch.StartNew(); ParallelWorks.WorkAsParallel(taskList, x => { Console.WriteLine("The long task {0} started at {1}", x, DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }); pwatch.Stop(); Console.WriteLine("WorkAsParallel done!"); var twatch = Stopwatch.StartNew(); ParallelProcessor.ExecuteParallel(delegate { Console.WriteLine("Task 1 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }, delegate { Console.WriteLine("Task 2 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }, delegate { Console.WriteLine("Task 3 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }, delegate { Console.WriteLine("Task 4 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }, delegate { Console.WriteLine("Task 5 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }, delegate { Console.WriteLine("Task 6 started at " + DateTime.Now.ToString("ss:fff")); Thread.Sleep(1000); }); twatch.Stop(); Console.WriteLine(); Console.WriteLine("WorkAsParallel finished in {0} seconds", pwatch.Elapsed.TotalSeconds); Console.WriteLine("ParallelProcessor finished in {0} seconds", twatch.Elapsed.TotalSeconds); // wait Console.ReadKey(); }
نتیجه اجرا چیزی مانند این خواهد بود (این نتیجه سیستم دو هسته من هست):
سلام دوست عزیز
پاسخحذفدر صفحه ی زیر لینک شده اید:
http://icnd.ir/pages/link
در صورت تمایل به تبادل لینک پس از درج لینک ICND.ir
در نظرات خبر دهید تا لینک شما در تمام صفحات قرار بگیرد.
متشکرم