新聞中心
博客前言

為什么要學(xué)習(xí)多線程?
2010年1月21日是10年某市公務(wù)員考試的報(bào)名截止日。因從下午2點(diǎn)開始,用于報(bào)名的北京市人事考試網(wǎng)癱瘓,原定于昨天下午5點(diǎn)截止的報(bào)名時(shí)間延遲至今天上午11點(diǎn)。
2011年3月11日下午5時(shí)(北京時(shí)間12日早9點(diǎn)),蘋果發(fā)布新一代的平板電腦產(chǎn)品iPad 2,配備了A5.1Ghz雙核處理器,這寓意著平板電腦和筆記本一同進(jìn)入"多核時(shí)代"。
同年6月18日,國內(nèi)著名B2C---京東在周年慶典之際舉行了"隆重"的大規(guī)模的促銷活動(dòng),搶購隨之而來,訂單擠爆京東 限時(shí)達(dá)臨時(shí)取消。 昨天有消費(fèi)者反映,由于點(diǎn)擊量過大,18日早上京東商城網(wǎng)站一度癱瘓。一位消費(fèi)者說:“18日凌晨1點(diǎn)開始就登不上京東商城?!眲?qiáng)東也表示:由于流量多 次超過4個(gè)G,服務(wù)器運(yùn)行緩慢。 昨天,京東商城官網(wǎng)發(fā)布公告稱,“‘618’活動(dòng)異?;鸨矣脩粝聠嗡俣瓤涨?,致使部分用戶已購訂單顯示出現(xiàn)延遲,用戶在一段時(shí)間內(nèi)無法在‘我的京東’中 查詢到自己的訂單。目前已購訂單顯示延遲的問題已得到有效解決,對(duì)此給您帶來的不便,我們深表歉意?!?/p>
2015年05月05日登錄風(fēng)信子網(wǎng)上商城發(fā)現(xiàn),首頁除了廣告和相關(guān)消息外,只有“注冊(cè)賬號(hào)獲取更多優(yōu)惠”這唯一一個(gè)按鈕,沒有商品展示,沒有產(chǎn) 品搜索,不能網(wǎng)上下單,甚至連進(jìn)入商城的按鈕也沒有。風(fēng)信子南沙跨境商品直購體驗(yàn)中心相關(guān)負(fù)責(zé)人表示,這主要是因?yàn)轭A(yù)約的人數(shù)太多,截至五一,預(yù)約人數(shù)已 超過十萬,太多人頻繁登陸,導(dǎo)致網(wǎng)店服務(wù)器癱瘓,目前技術(shù)人員還在努力維修中。該負(fù)責(zé)人介紹,體驗(yàn)中心的網(wǎng)站目前正在調(diào)試,“網(wǎng)站目前的作用主要是給市民 預(yù)約和提前注冊(cè),通過網(wǎng)絡(luò)注冊(cè)的市民不用在現(xiàn)場(chǎng)驗(yàn)證身份證等信息,可以提高購買效率。”
下面通過一些實(shí)例來認(rèn)識(shí)一下多線程和讓大家知道為什么要學(xué)習(xí)多線程。
寫在前面
老板只有兩種,好的和壞的。好的老板只跟你談錢,壞的老板只跟你談理想。
v模擬場(chǎng)景
假設(shè)后臺(tái)有個(gè)monitor時(shí)事的在監(jiān)測(cè)訂單,且可以發(fā)現(xiàn)訂單然后處理訂單,每次(1次/S)可以處理1千個(gè)訂單,需要向倉庫系統(tǒng)發(fā)出指令,讓他們負(fù)責(zé)配送發(fā)貨。那么我們來寫一個(gè)EmulationSystem(模擬系統(tǒng))
JobHelper因?yàn)槲覀冎皇菫榱四M一個(gè)環(huán)境,所以它是這樣的。
- //------------------------------------------------------------------------------
- //
- // Copyright (C) 2015-2016 All Rights Reserved
- // 原博文地址: http://www.cnblogs.com/toutou/
- //
- //------------------------------------------------------------------------------
- namespace CNBlogs.Common.Shared
- {
- using System.Threading;
- ///
- /// Job helper
- ///
- public class JobHelper
- {
- ///
- /// Get job total count
- ///
- ///
- public int GetJobCount()
- {
- // 我們的側(cè)重點(diǎn)是多線程,所以我們就模擬每次有1千個(gè)訂單,而模擬,所以我們不關(guān)心其他的。只要訂單數(shù)量。
- return 1000;
- }
- ///
- /// Submit job
- ///
- /// For job id
- ///
Submit job status - public bool SubmitJob(int jobId)
- {
- // 假設(shè)針對(duì)每個(gè)訂單向后臺(tái)發(fā)送任務(wù)需要1秒,而且每個(gè)訂單都能成功發(fā)送
- Thread.Sleep(1000);
- return true;
- }
- }
- }
背景我們也交待完了,現(xiàn)在需要來得到這些訂單信息以后,向倉庫submit這些訂單。
v實(shí)戰(zhàn)演習(xí)
根據(jù)這種背景,我們可以有很多處理的辦法。
-
傳統(tǒng)辦法:
(開啟無腦模式:未使用多線程)
代碼正文:
- //------------------------------------------------------------------------------
- //
- // Copyright (C) 2015-2016 All Rights Reserved
- // 原博文地址: http://www.cnblogs.com/toutou/
- //
- //------------------------------------------------------------------------------
- namespace CNBlogs.EmulationSystem
- {
- using System;
- using System.Threading;
- using CNBlogs.Common.Shared;
- class Runner
- {
- ///
- /// Job helper
- ///
- private static JobHelper jobHelper = new JobHelper();
- ///
- /// Runner lock
- ///
- private static Mutex mutex;
- static void Main(string[] args)
- {
- // 記錄開始處理的時(shí)間
- DateTime paddingTime = DateTime.Now.ToLocalTime();
- int orderCount = jobHelper.GetJobCount();
- // 用一個(gè)指示調(diào)用線程是否應(yīng)擁有互斥體的初始所屬權(quán)的布爾值來初始化 Mutex 類的新實(shí)例。
- // 當(dāng)前進(jìn)程只能啟動(dòng)一次
- mutex = new Mutex(false, "CNBlogs.EmulationSystem");
- if (!mutex.WaitOne(0, false))
- {
- Console.Out.WriteLine("Monitor already running...");
- return;
- }
- for (int i = 0; i < orderCount; i++)
- {
- // 假設(shè)i就是job id
- jobHelper.SubmitJob(i);
- }
- // 記錄處理完成的時(shí)間
- DateTime completeTime = DateTime.Now.ToLocalTime();
- var minutes = (completeTime - paddingTime).TotalSeconds;
- Console.WriteLine(string.Format("處理{0}個(gè)訂單,花費(fèi)時(shí)間{1}秒", orderCount, minutes));
- }
- }
- }
PS:現(xiàn)在的這些個(gè)電商,動(dòng)不動(dòng)來個(gè)什么周年慶店慶什么雙11雙12的一頓突突,搞得咱這些老百姓就全部蜂擁而上,顯然如果用傳統(tǒng)的方法雖然不會(huì)出錯(cuò),但是老板肯定會(huì)找你喝茶。在多核時(shí)代用這種方法也只能恨鐵不成鋼了。所以這個(gè)方法是絕對(duì)不可取的。
-
Task方法:
如果有對(duì)Task不是很熟悉的園友可以在這里解開心謎。
代碼正文:
- //------------------------------------------------------------------------------
- //
- // Copyright (C) 2015-2016 All Rights Reserved
- // 原博文地址: http://www.cnblogs.com/toutou/
- //
- //------------------------------------------------------------------------------
- namespace CNBlogs.EmulationSystem
- {
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using System.Threading.Tasks;
- using CNBlogs.Common.Shared;
- class Runner
- {
- ///
- /// Job helper
- ///
- private static JobHelper jobHelper = new JobHelper();
- ///
- /// Runner lock
- ///
- private static Mutex mutex;
- static void Main(string[] args)
- {
- // 記錄開始處理的時(shí)間
- DateTime paddingTime = DateTime.Now.ToLocalTime();
- int orderCount = jobHelper.GetJobCount();
- // 用一個(gè)指示調(diào)用線程是否應(yīng)擁有互斥體的初始所屬權(quán)的布爾值來初始化 Mutex 類的新實(shí)例。
- // 當(dāng)前進(jìn)程只能啟動(dòng)一次
- mutex = new Mutex(false, "CNBlogs.EmulationSystem");
- if (!mutex.WaitOne(0, false))
- {
- Console.Out.WriteLine("Monitor already running...");
- return;
- }
- var taskList = new List
(); - for (int i = 0; i < orderCount; i++)
- {
- int temp=i;
- taskList.Add(Task.Factory.StartNew(() =>
- {
- // 假設(shè)i就是job id
- jobHelper.SubmitJob(temp);
- }));
- }
- // 等待所有task執(zhí)行完畢
- Task.WaitAll(taskList.ToArray());
- // 記錄處理完成的時(shí)間
- DateTime completeTime = DateTime.Now.ToLocalTime();
- var minutes = (completeTime - paddingTime).TotalSeconds;
- Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes));
- }
- }
- }
代碼效果:
相信分別從有TASK和沒有TASK的這兩次demo中,可以清楚的發(fā)現(xiàn)多線程處理這些頻繁交互能力的魅力。你會(huì)愛上這個(gè)方法。確實(shí)提高的效率。但是問題也隨之而來,一個(gè)進(jìn)程多線程的總數(shù)和大小是有要求的(這個(gè)取決于服務(wù)器的配置),不是任由我們肆意的開采的。如果訂單太多,我們不控制task那是會(huì)拉仇恨的。task需要控制。
-
Semaphore:
如果有對(duì)Semaphore不是很熟悉的園友可以在這里解開心謎。
代碼正文:
- //------------------------------------------------------------------------------
- //
- // Copyright (C) 2015-2016 All Rights Reserved
- // 原博文地址: http://www.cnblogs.com/toutou/
- //
- //------------------------------------------------------------------------------
- namespace CNBlogs.EmulationSystem
- {
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using System.Threading.Tasks;
- using CNBlogs.Common.Shared;
- class Runner
- {
- ///
- /// Job helper
- ///
- private static JobHelper jobHelper = new JobHelper();
- ///
- /// The locker used to lock the semaphore and thread.
- ///
- private static object lockerObj = new object();
- ///
- /// The semaphore limit the thread number of get latest test info
- ///
- private static Semaphore semaphoreLimit;
- ///
- /// Runner lock
- ///
- private static Mutex mutex;
- static void Main(string[] args)
- {
- // 記錄開始處理的時(shí)間
- DateTime paddingTime = DateTime.Now.ToLocalTime();
- int orderCount = jobHelper.GetJobCount();
- // 用一個(gè)指示調(diào)用線程是否應(yīng)擁有互斥體的初始所屬權(quán)的布爾值來初始化 Mutex 類的新實(shí)例。
- // 當(dāng)前進(jìn)程只能啟動(dòng)一次
- mutex = new Mutex(false, "CNBlogs.EmulationSystem");
- if (!mutex.WaitOne(0, false))
- {
- Console.Out.WriteLine("Monitor already running...");
- return;
- }
- // 假設(shè)我們的服務(wù)器一個(gè)進(jìn)程只能接受的大小=當(dāng)前線程大小*500 ps:500是設(shè)置信號(hào)量的最大值
- int maxProcNumber = 500;
- using (semaphoreLimit = new Semaphore(0, maxProcNumber))
- {
- // 以指定的次數(shù)退出信號(hào)量并返回前一個(gè)計(jì)數(shù)。
- semaphoreLimit.Release(maxProcNumber);
- var taskList = new List
(); - for (int i = 0; i < orderCount; i++)
- {
- int temp=i;
- // 如果SubmitJob有IO或者其他容易因?yàn)闆_突而引起異常的話,這里需要加上lock
- //lock (lockerObj)
- //{
- semaphoreLimit.WaitOne();
- taskList.Add(Task.Factory.StartNew(() =>
- {
- // 假設(shè)i就是job id
- jobHelper.SubmitJob(temp);
- // 退出信號(hào)量并返回前一個(gè)計(jì)數(shù)。
- semaphoreLimit.Release();
- }));
- //}
- }
- // 等待所有task執(zhí)行完畢
- Task.WaitAll(taskList.ToArray());
- }
- // 記錄處理完成的時(shí)間
- DateTime completeTime = DateTime.Now.ToLocalTime();
- var minutes = (completeTime - paddingTime).TotalSeconds;
- Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes));
- }
- }
- }
代碼效果:
v博客總結(jié)
多線程路還很長...
當(dāng)前標(biāo)題:C#多線程,論多核時(shí)代愛恨情仇
鏈接分享:http://www.dlmjj.cn/article/ccsgjge.html


咨詢
建站咨詢
