日本好好热aⅴ|国产99视频精品免费观看|日本成人aV在线|久热香蕉国产在线

  • <cite id="ikgdy"><table id="ikgdy"></table></cite>
    1. 西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
      軟件
      軟件
      文章
      搜索

      首頁編程開發(fā)C#.NET → C#中幾種常見的異步處理的方法

      C#中幾種常見的異步處理的方法

      相關(guān)軟件相關(guān)文章發(fā)表評論 來源:本站整理時(shí)間:2010/11/13 0:15:55字體大。A-A+

      作者:佚名點(diǎn)擊:637次評論:3次標(biāo)簽: 異步處理

      • 類型:教育學(xué)習(xí)大。110KB語言:中文 評分:7.5
      • 標(biāo)簽:
      立即下載
      先大概看一下控制臺應(yīng)用程序的Main方法的主要代碼:

      001 static bool done = false;

      002 static decimal count2 = 0;

      003 static int threadDone = 0;//標(biāo)志啟用線程數(shù)?

      004 static System.Timers.Timer timer = new System.Timers.Timer(1000);

      005

      006 static decimal[] threadPoolCounters = new decimal[10];

      007 static Thread[] threads = new Thread[10];

      008 static System.Timers.Timer[] threadTimers = new System.Timers.Timer[10];

      009

      010 static void Main(string[] args)

      011 {

      012 timer.Stop();

      013 /*當(dāng) AutoReset 設(shè)置為 false 時(shí),Timer 只在第一個 Interval 過后引發(fā)一次 Elapsed 事件。

      014 若要保持以 Interval 時(shí)間間隔引發(fā) Elapsed 事件,請將 AutoReset 設(shè)置為 true。*/

      015 timer.AutoReset = false;

      016 timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//當(dāng)timer.Start()時(shí),觸發(fā)事件

      017 decimal total = 0;

      018

      019 // raw test

      020 decimal count1 = SingleThreadTest();//單一線程,一跑到底

      021 Console.WriteLine("Single thread count = " + count1.ToString());

      022

      023 // create one thread, increment counter, destroy thread, repeat

      024 Console.WriteLine();

      025 CreateAndDestroyTest();//創(chuàng)建一個線程,運(yùn)算,然后銷毀該線程 重復(fù)前面的動作

      026 Console.WriteLine("Create and destroy per count = " + count2.ToString());

      027

      028 // Create 10 threads and run them simultaneously

      029 //一次性創(chuàng)建10個線程,然后遍歷使線程執(zhí)行運(yùn)算

      030 Console.WriteLine();

      031 InitThreadPoolCounters();

      032 InitThreads();

      033 StartThreads();

      034 while (threadDone != 10) { };

      035 Console.WriteLine("10 simultaneous threads:");

      036 for (int i = 0; i < 10; i++)

      037 {

      038 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      039 total += threadPoolCounters[i];

      040 }

      041 Console.WriteLine("Total = " + total.ToString());

      042 Console.WriteLine();

      043

      044 Console.WriteLine("http:///////////////////////////////////////////////////");

      045

      046 // using ThreadPool

      047 //直接通過線程池的QueueUserWorkItem方法,按隊(duì)列執(zhí)行10個任務(wù)

      048 Console.WriteLine();

      049 Console.WriteLine("ThreadPool:");

      050 InitThreadPoolCounters();

      051 QueueThreadPoolThreads();

      052 while (threadDone != 10) { };

      053 Console.WriteLine("ThreadPool: 10 simultaneous threads:");

      054 total = 0;

      055 for (int i = 0; i < 10; i++)

      056 {

      057 // threadTimers[i].Stop();

      058 // threadTimers[i].Dispose();

      059 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      060 total += threadPoolCounters[i];

      061 }

      062 Console.WriteLine("Total = " + total.ToString());

      063

      064 // using SmartThreadPool

      065 //通過Amir Bar的SmartThreadPool線程池,利用QueueUserWorkItem方法,按隊(duì)列執(zhí)行10個任務(wù)

      066 Console.WriteLine();

      067 Console.WriteLine("SmartThreadPool:");

      068 InitThreadPoolCounters();

      069 QueueSmartThreadPoolThreads();

      070 while (threadDone != 10) { };

      071 Console.WriteLine("SmartThreadPool: 10 simultaneous threads:");

      072 total = 0;

      073 for (int i = 0; i < 10; i++)

      074 {

      075 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      076 total += threadPoolCounters[i];

      077 }

      078 Console.WriteLine("Total = " + total.ToString());

      079

      080 // using ManagedThreadPool

      081 //通過Stephen Toub改進(jìn)后的線程池,利用QueueUserWorkItem方法,按隊(duì)列執(zhí)行10個任務(wù)

      082 Console.WriteLine();

      083 Console.WriteLine("ManagedThreadPool:");

      084 InitThreadPoolCounters();

      085 QueueManagedThreadPoolThreads();

      086 while (threadDone != 10) { };

      087 Console.WriteLine("ManagedThreadPool: 10 simultaneous threads:");

      088 total = 0;

      089 for (int i = 0; i < 10; i++)

      090 {

      091 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      092 total += threadPoolCounters[i];

      093 }

      094 Console.WriteLine("Total = " + total.ToString());

      095

      096 // using C#4.0 Parallel

      097 //通過Tasks.Parallel.For進(jìn)行并行運(yùn)算

      098 Console.WriteLine();

      099 Console.WriteLine("Parallel:");

      100 InitThreadPoolCounters();

      101 UseParallelTasks();

      102 while (threadDone != 10) { };

      103 Console.WriteLine("Parallel: 10 simultaneous threads:");

      104 total = 0;

      105 for (int i = 0; i < 10; i++)

      106 {

      107 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      108 total += threadPoolCounters[i];

      109 }

      110 Console.WriteLine("Total = " + total.ToString());

      111 }

      我們可以先熟悉一下大致思路。代碼中,我們主要依靠輸出的數(shù)字count或者total來判斷哪個方法執(zhí)行效率更高(原文是How Hign Can I Count?),通常輸出的數(shù)字越大,我們就認(rèn)為它”干的活越多“,效率越高。主要實(shí)現(xiàn)過程就是通過一個靜態(tài)的System.Timers.Timer對象的timer實(shí)例,設(shè)置它的Interval屬性和ElapsedEventHandler事件:

      1 static System.Timers.Timer timer = new System.Timers.Timer(1000);

      2 /*當(dāng) AutoReset 設(shè)置為 false 時(shí),Timer 只在第一個 Interval 過后引發(fā)一次 Elapsed 事件。

      3 若要保持以 Interval 時(shí)間間隔引發(fā) Elapsed 事件,請將 AutoReset 設(shè)置為 true。*/

      4 timer.AutoReset = false;

      5 timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//當(dāng)timer.Start()時(shí),觸發(fā)事件

      其中,timer的事件觸發(fā)的函數(shù):

      ?1 static void OnTimerEvent(object src, ElapsedEventArgs e)

      2 {

      3 done = true;

      4 }

      每次timer.Start執(zhí)行的時(shí)候,一次測試就將開始,這樣可以確保測試的不同方法都在1000毫秒內(nèi)跑完。

      下面開始具體介紹幾個方法:

      A、線程

      這個非常簡單,就是通過主線程計(jì)算在1000毫秒內(nèi),count從0遞增加到了多少:

      01 /// <summary>

      02 /// 單一線程,一跑到底

      03 /// </summary>

      04 /// <returns></returns>

      05 static decimal SingleThreadTest()

      06 {

      07 done = false;

      08 decimal counter = 0;

      09 timer.Start();

      10 while (!done)

      11 {

      12 ++counter;

      13 }

      14 return counter;

      15 }

      while判斷可以保證方法在1000毫秒內(nèi)執(zhí)行完成。



      B、多線程

      這個多線程方法比較折騰,先創(chuàng)建線程,然后運(yùn)行,最后銷毀線程,這就是一個線程執(zhí)行單元,重復(fù)10次這個線程執(zhí)行單元。

      01 /// <summary>

      02 /// 創(chuàng)建一個線程,運(yùn)算,然后銷毀該線程 重復(fù)前面的動作

      03 /// </summary>

      04 static void CreateAndDestroyTest()

      05 {

      06 done = false;

      07 timer.Start();

      08 while (!done)

      09 {

      10 Thread counterThread = new Thread(new ThreadStart(Count1Thread));

      11 counterThread.IsBackground = true;//后臺線程

      12 counterThread.Start();

      13 while (counterThread.IsAlive) { };

      14 }

      15 }

      那個ThreadStart委托對應(yīng)的方法Count1Thread如下:

      ?1 static void Count1Thread()

      2 {

      3 ++count2; //靜態(tài)字段count2自增

      4 }

      從表面上看,大家估計(jì)都可以猜到,效果可能不佳。



      C、還是多線程

      這個方法不判斷線程的執(zhí)行狀態(tài),不用等到一個線程銷毀后再創(chuàng)建一個線程,然后執(zhí)行線程方法。線程執(zhí)行的方法就是根據(jù)線程的Name找到一個指定數(shù)組的某一索引,并累加改變數(shù)組的值:

      01 /// <summary>

      02 /// 將數(shù)組和線程數(shù)標(biāo)志threadDone回到初始狀態(tài)

      03 /// </summary>

      04 static void InitThreadPoolCounters()

      05 {

      06 threadDone = 0;

      07 for (int i = 0; i < 10; i++)

      08 {

      09 threadPoolCounters[i] = 0;

      10 }

      11 }

      12

      13 /// <summary>

      14 /// 初始化10個線程

      15 /// </summary>

      16 static void InitThreads()

      17 {

      18 for (int i = 0; i < 10; i++)

      19 {

      20 threads[i] = new Thread(new ThreadStart(Count2Thread));

      21 threads[i].IsBackground = true;

      22 threads[i].Name = i.ToString();//將當(dāng)前線程的Name賦值為數(shù)組索引,在Count2Thread方法中獲取對應(yīng)數(shù)組

      23 }

      24 }

      25

      26 /// <summary>

      27 /// 開始多線程運(yùn)算

      28 /// </summary>

      29 static void StartThreads()

      30 {

      31 done = false;

      32 timer.Start();

      33 for (int i = 0; i < 10; i++)

      34 {

      35 threads[i].Start();

      36 }

      37 }

      其中,每一個線程需要執(zhí)行的委托方法

      1 static void Count2Thread()

      2 {

      3 int n = Convert.ToInt32(Thread.CurrentThread.Name);//取數(shù)組索引

      4 while (!done)

      5 {

      6 ++threadPoolCounters[n];

      7 }

      8 Interlocked.Increment(ref threadDone);//以原子操作的形式保證threadDone遞增

      9 }

      在測試過程中,我們看代碼:

      01 // Create 10 threads and run them simultaneously

      02 //一次性創(chuàng)建10個線程,然后遍歷使線程執(zhí)行運(yùn)算

      03 Console.WriteLine();

      04 InitThreadPoolCounters();

      05 InitThreads();

      06 StartThreads();

      07 while (threadDone != 10) { };

      08 Console.WriteLine("10 simultaneous threads:");

      09 for (int i = 0; i < 10; i++)

      10 {

      11 Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

      12 total += threadPoolCounters[i];

      13 }

      14 Console.WriteLine("Total = " + total.ToString());

      15 Console.WriteLine();

      最后算出這個數(shù)組的所有元素的總和,就是這10個線程在1000毫秒內(nèi)所做的事情。其中, while (threadDone != 10) { };這個判斷非常重要。這個方法看上去沒心沒肺,線程創(chuàng)建好就不管它的死活了(還是管活不管死?),所以效率應(yīng)該不低。

      實(shí)際上,我在本地測試并看了一下輸出,表面看來,按count大小逆序排列:C>A>B,這就說明多線程并不一定比單線程運(yùn)行效率高。其實(shí)B之所以效率不佳,主要是由于這個方法大部分的”精力“花在線程的執(zhí)行狀態(tài)和銷毀處理上。

      注意,其實(shí)C和A、B都沒有可比性,因?yàn)镃計(jì)算的是數(shù)組的總和,而A和B只是簡單的對一個數(shù)字進(jìn)行自加。

      ps:C這一塊說的沒有中心,想到哪寫到哪,所以看起來寫得很亂,如果看到這里您還覺著不知所云,建議先下載最后的demo,先看代碼,再對照這篇文章。

      好了,到這里,我們對線程的創(chuàng)建和使用應(yīng)該有了初步的了解。細(xì)心的人可能會發(fā)現(xiàn),我們new一個Thread,然后給線程實(shí)例設(shè)置屬性,比如是否后臺線程等等,其實(shí)這部分工作可以交給下面介紹的線程池ThreadPool來做(D、E和F主要介紹線程池)。



      D、線程池ThreadPool

      在實(shí)際的項(xiàng)目中大家可能使用最多最熟悉的就是這個類了,所以沒什么可說的:

      01 /// <summary>

      02 /// ThreadPool測試

      03 /// </summary>

      04 static void QueueThreadPoolThreads()

      05 {

      06 done = false;

      07 for (int i = 0; i < 10; i++)

      08 {

      09 ThreadPool.QueueUserWorkItem(new WaitCallback(Count3Thread), i);

      10 }

      11

      12 timer.Start();

      13 }

      14

      15 static void Count3Thread(object state)

      16 {

      17 int n = (int)state;

      18 while (!done)

      19 {

      20 ++threadPoolCounters[n];

      21 }

      22 Interlocked.Increment(ref threadDone);

      23 }

      我們知道線程池里的線程默認(rèn)都是后臺線程,所以它實(shí)際上簡化了線程的屬性設(shè)置,更方便異步編程。

      需要說明的是,線程池使用過程中會有這樣那樣的缺陷(雖然本文的幾個線程池任務(wù)都不會受這種缺陷影響)。比如,我們一次性向線程池中加入100個任務(wù),但是當(dāng)前的系統(tǒng)可能只支持25個線程,并且每個線程正處于”忙碌“狀態(tài),如果一次性加入池中系統(tǒng)會處理不過來,那么多余的任務(wù)必須等待,這就造成等待的時(shí)間過長,系統(tǒng)無法響應(yīng)。還好,ThreadPool提供了GetAvailableThreads方法,可以讓你知道當(dāng)前可用的工作線程數(shù)量。

      01 static void QueueThreadPoolThreads()

      02 {

      03 done = false;

      04 for (int i = 0; i < 10; i++)

      05 {

      06 //ThreadPool.QueueUserWorkItem(new WaitCallback(Count3Thread), i); //直接給程序池添加任務(wù)有時(shí)是很草率的

      07

      08 WaitCallback wcb = new WaitCallback(Count3Thread);

      09 int workerThreads, availabeThreads;

      10 ThreadPool.GetAvailableThreads(out workerThreads, out availabeThreads);

      11 if (workerThreads > 0)//可用線程數(shù)>0

      12 {

      13 ThreadPool.QueueUserWorkItem(wcb, i);

      14 }

      15 else

      16 {

      17 //to do 可以采取一種策略,讓這個任務(wù)合理地分配給線程

      18 }

      19 }

      如果沒有可用的工作線程數(shù),必須設(shè)計(jì)一定的策略,讓這個任務(wù)合理地分配給線程。

      也許就是類似于上面那樣的限制,很多開發(fā)者都自己創(chuàng)建自己的線程池,同時(shí)也就有了后面的SmartThreadPool和ManagedThreadPool大展身手的機(jī)會。



      E、線程池SmartThreadPool

      大名鼎鼎的SmartThreadPool,但是我從來沒在項(xiàng)目中使用過,所以只是找了一段簡單的代碼測試一下:

      01 /// <summary>

      02 /// SmartThreadPool測試

      03 /// </summary>

      04 static void QueueSmartThreadPoolThreads()

      05 {

      06 SmartThreadPool smartThreadPool = new SmartThreadPool();

      07 // Create a work items group that processes

      08 // one work item at a time

      09 IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);

      10

      11 done = false;

      12 timer.Start();

      13 for (int i = 0; i < 10; i++)

      14 {

      15 wig.QueueWorkItem(new WorkItemCallback(Count4Thread), i);

      16 }

      17 // Wait for the completion of all work items in the work items group

      18 wig.WaitForIdle();

      19 smartThreadPool.Shutdown();

      20 }

      21

      22 static object Count4Thread(object state)

      23 {

      24 int n = (int)state;

      25 while (!done)

      26 {

      27 ++threadPoolCounters[n];

      28 }

      29 Interlocked.Increment(ref threadDone);

      30 return null;

      31 }

      自從收藏這個SmartThreadPool.dll后,我還從沒有在項(xiàng)目中使用過。查看它的源碼注釋挺少也挺亂的,不知道有沒有高人知道它的一個效率更好的方法。您也可以看看英文原文,自己嘗試體驗(yàn)一下。如果您熟悉使用SmartThreadPool,歡迎討論。



      F、線程池ManagedThreadPool

      Stephen Toub這個完全用C#托管代碼實(shí)現(xiàn)的線程池也非常有名,在Marc Clifton的英文原文中,作者也不吝溢美之詞,贊它“quite excellent”,于我心有戚戚焉:

      01 /// <summary>

      02 /// ManagedThreadPool測試

      03 /// </summary>

      04 static void QueueManagedThreadPoolThreads()

      05 {

      06 done = false;

      07 timer.Start();

      08 for (int i = 0; i < 10; i++)

      09 {

      10 Toub.Threading.ManagedThreadPool.QueueUserWorkItem(new WaitCallback(Count5Thread), i);

      11 }

      12 }

      13 static void Count5Thread(object state)

      14 {

      15 int n = (int)state;

      16 while (!done)

      17 {

      18 ++threadPoolCounters[n];

      19 }

      20 Interlocked.Increment(ref threadDone);

      21 }


      對于這個托管的線程池,我個人的理解,就是它在管理線程的時(shí)候,這個池里還有一個緩存線程的池,即一個ArrayList對象。它一開始就初始化了一定數(shù)量的線程,并通過ProcessQueuedItems方法保證異步執(zhí)行進(jìn)入池中的隊(duì)列任務(wù)(那個死循環(huán)有時(shí)可能導(dǎo)致CPU過分忙碌),這樣在分配異步任務(wù)的時(shí)候,就省去了頻繁去創(chuàng)建(new)一個線程。同時(shí)它在實(shí)現(xiàn)信號量(Semaphore)的同步和線程出入隊(duì)列的設(shè)計(jì)上都可圈可點(diǎn),非常巧妙,強(qiáng)烈推薦您閱讀它的源碼。


      G、并行運(yùn)算

      下面的示例,我只使用了簡單的System.Threading.Tasks.Parallel.For 對應(yīng)的for 循環(huán)的并行運(yùn)算:

      01 /// <summary>

      02 /// 并行運(yùn)算測試

      03 /// </summary>

      04 static void UseParallelTasks()

      05 {

      06 done = false;

      07 timer.Start();

      08 // System.Threading.Tasks.Parallel.For - for 循環(huán)的并行運(yùn)算

      09 System.Threading.Tasks.Parallel.For(0, 10, (i) => { Count6Thread(i); });

      10 }

      11 static void Count6Thread(object state)

      12 {

      13 int n = (int)state;

      14 while (!done)

      15 {

      16 ++threadPoolCounters[n];

      17 }

      18 Interlocked.Increment(ref threadDone);

      19 }

      沒有什么要特殊說明的,就是新類庫的使用。看代碼,好像比使用線程或線程池更加簡單直接,有機(jī)會爭取多用一用。我在本地測試的時(shí)候,在Release版本下,按照count的大小逆序排列,總體上G>D>F>E。需要注意到一件事,就是SmartThreadPool中排入隊(duì)列的任務(wù)是一個返回值為Object的委托類型,這和其他的幾個沒有返回的(void類型)不同。SmartThreadPool口碑還是不錯的,也許是我沒有正確使用它。


      最后小結(jié)一下:本文主要列舉了C#中我所知道的幾種常見的異步處理的方法,歡迎大家糾錯或補(bǔ)充。
        進(jìn)制轉(zhuǎn)換器
        (20)進(jìn)制轉(zhuǎn)換器
        某些時(shí)候我們經(jīng)常會用到進(jìn)制轉(zhuǎn)換,特別是涉及到計(jì)算機(jī)領(lǐng)域,編寫各種程序。這種情況下一款簡單方便的進(jìn)制轉(zhuǎn)換工具可以幫我們節(jié)約大量時(shí)間,你要做的就是輸入值,然后按一個按鈕可以即時(shí)查看結(jié)果。這里西西為大家整理了二進(jìn)制四進(jìn)制八進(jìn)制十進(jìn)制十六進(jìn)制三十二進(jìn)制六十四進(jìn)制等各類進(jìn)制轉(zhuǎn)換工具。...更多>>
        • UltraEdit-32v23.0.0.59 烈火漢化綠

          03-31 / 33.8M

          推薦理由:本次已經(jīng)糾正官方多處翻譯錯誤地方,UltraEdit是能夠滿足你一切編輯需要的編輯器。UltraEdit是一套功能強(qiáng)大
        • 16進(jìn)制轉(zhuǎn)換工具V1.0 中文綠色版

          11-08 / 388KB

          推薦理由:在反編譯中出現(xiàn)的一般是16進(jìn)制代碼,可以準(zhǔn)確快速轉(zhuǎn)換2、10、16、字節(jié)、文本互相轉(zhuǎn)換.支持多種進(jìn)制互相轉(zhuǎn)換
        • WinHex 十六進(jìn)制編輯器v18.7 綠色中

          02-04 / 2.8M

          推薦理由:WinHex 是一款以十六進(jìn)制編輯器為核心的數(shù)據(jù)處理高級工具,雖然我們更喜歡稱之為十六進(jìn)制編輯器,但它確實(shí)有
        • 安卓十六進(jìn)制編輯器(Hex Editor)v2

          04-14 / 998KB

          推薦理由:十六進(jìn)制編輯器 Hex Editor 是一款簡單實(shí)用的文件編輯器工具,通過它能快速查找和修改文件內(nèi)容。軟件為默認(rèn)
        • 4種常用進(jìn)制轉(zhuǎn)換器V5.0.0.3綠色版

          07-10 / 110KB

          推薦理由:2、8、10和16這4種常用進(jìn)制的轉(zhuǎn)換。1. 本軟件用于二進(jìn)制、 八進(jìn)制、 十進(jìn)制和十六進(jìn)制之間實(shí)數(shù)的相互轉(zhuǎn)換。
        • 2到62進(jìn)制轉(zhuǎn)換器V5.5.0.3 綠色版

          07-10 / 110KB

          推薦理由:本轉(zhuǎn)換器可用于任意位整數(shù)、任意位小數(shù)、2到62進(jìn)制的轉(zhuǎn)換。1. 本軟件用于2進(jìn)制到62進(jìn)制之間實(shí)數(shù)的相互轉(zhuǎn)換。

        相關(guān)評論

        閱讀本文后您有什么感想? 已有人給出評價(jià)!

        • 8 喜歡喜歡
        • 3 頂
        • 1 難過難過
        • 5 囧
        • 3 圍觀圍觀
        • 2 無聊無聊

        熱門評論

        最新評論

        發(fā)表評論 查看所有評論(3)

        昵稱:
        表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
        字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)