C# Parallel.For的使用

1 緣起

實(shí)驗(yàn)室接了一個(gè)新的項(xiàng)目辜荠,需要在一塊3d地形上基于速度繪上顏色瘤缩,而且要?jiǎng)討B(tài)改變紊服。由于地形比較大伺糠,mesh網(wǎng)格的頂點(diǎn)一共有一千三百多萬(wàn)個(gè)蒙谓,即使在邏輯上優(yōu)化之后也達(dá)到了一百多萬(wàn)個(gè)。使用傳統(tǒng)的for循環(huán)為每個(gè)頂點(diǎn)賦顏色值训桶,效率太低累驮,最終的fps只能達(dá)到8左右,完全達(dá)不到項(xiàng)目要求渊迁。在老師的指導(dǎo)下慰照,開(kāi)始考慮多線(xiàn)程的方法提高效率。

2 Parallel.For

在查閱了大量網(wǎng)絡(luò)資源之后琉朽,確定了最簡(jiǎn)單易行的方法是C#本身提供的Parallel并行計(jì)算方法毒租。

關(guān)于Parallel.For的語(yǔ)法就不細(xì)說(shuō)了,直接通過(guò)下面的代碼見(jiàn)識(shí)一下并行的威力吧箱叁。

using System.Diagnostics;
using System.Threading.Tasks;
using UnityEngine;

public class testParallel : Mono Behaviour
{
    Stopwatch stopWatch = new Stopwatch();
    void Start()
    {
        stopWatch.Start();
        for (int i = 0; i < 10000; i++)
        {
            for (int j = 0; j < 60000; j++)
            {
                int sum = 0;
                sum += i;
            }
        }
        stopWatch.Stop();
        print("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

        stopWatch.Reset();
        stopWatch.Start();
        Parallel.For(0, 10000, item =>
        {
            for (int j = 0; j < 60000; j++)
            {
                int sum = 0;
                sum += item;
            }
        });
        stopWatch.Stop();
        print("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
    }
}

在unity中運(yùn)行該代碼墅垮,其結(jié)果如下圖所示

可以發(fā)現(xiàn),Parallel.For相較于傳統(tǒng)的for循環(huán)運(yùn)行時(shí)間加快了1s耕漱。而在本次項(xiàng)目中算色,在使用了Parallel.For的情況下,fps直接達(dá)到了23螟够,這是一個(gè)相當(dāng)大的提升了灾梦。

3 深入思考

在體驗(yàn)到Parallel.For的巨大優(yōu)勢(shì)之后峡钓,我不禁思考:

  1. 是不是所有的Parallel.For都比傳統(tǒng)的for循環(huán)都快呢?
  2. 今后我是不是可以把所有的for循環(huán)都替換為Parallel.For呢?

帶著這樣的問(wèn)題,我繼續(xù)搜索若河,也發(fā)現(xiàn)了使用Parallel.For的一些注意事項(xiàng)能岩。

3.1 Parallel.For的快是有前提的

眾所周知,在實(shí)現(xiàn)多線(xiàn)程時(shí)萧福,為了防止多個(gè)線(xiàn)程同時(shí)處理同一個(gè)變量而導(dǎo)致變量處于"薛定諤狀態(tài)"拉鹃,引入了"鎖"的概念,即在每一時(shí)刻只有獲得"鎖"的線(xiàn)程才能操作目標(biāo)變量鲫忍。那么如果在Parallel.For中也需要操作一個(gè)全局變量膏燕,就意味著即使這是并行計(jì)算,大家也需要排隊(duì)操作全局變量悟民,此時(shí)Parallel.For可能遠(yuǎn)遠(yuǎn)不如傳統(tǒng)的for循環(huán)來(lái)的快坝辫。

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading.Tasks;
using UnityEngine;

public class testParallel : MonoBehaviour
{
    Stopwatch stopWatch = new Stopwatch();
    void Start()
    {
        var obj = new Object();
        long num = 0;
        ConcurrentBag<long> bag = new ConcurrentBag<long>();

        stopWatch.Start();
        for (int i = 0; i < 10000; i++)
        {
            for (int j = 0; j < 60000; j++)
            {
                num++;
            }
        }
        stopWatch.Stop();
        print("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

        stopWatch.Reset();
        stopWatch.Start();
        Parallel.For(0, 10000, item =>
        {
            for (int j = 0; j < 60000; j++)
            {
                lock (obj)
                {
                    num++;
                }
            }
        });
        stopWatch.Stop();
        print("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");
    }
}

在unity中運(yùn)行該代碼,其結(jié)果如下圖所示

可以發(fā)現(xiàn)射亏,Parallel.For的運(yùn)行時(shí)間竟然是傳統(tǒng)for循環(huán)運(yùn)行時(shí)間的100倍阀溶!因此可以得出結(jié)論:

如果在循環(huán)中需要競(jìng)爭(zhēng)資源,用到線(xiàn)程鎖的話(huà)鸦泳,Parallel.For未必優(yōu)于傳統(tǒng)for循環(huán)

3.2 Parallel.For的循環(huán)是無(wú)序的

由于Parallel.For中的各個(gè)循環(huán)是同時(shí)進(jìn)行的银锻,所以每次循環(huán)體執(zhí)行的時(shí)間會(huì)有些許差異,這就導(dǎo)致了循環(huán)的運(yùn)行是無(wú)序的做鹰。

using System.Threading.Tasks;
using UnityEngine;

public class testParallel : MonoBehaviour
{
    void Start()
    {
        Parallel.For(0, 5, item =>
        {
            print(item);
        });
    }
}

在unity中運(yùn)行該代碼击纬,其結(jié)果如下圖所示

因此可以得出結(jié)論:

如果循環(huán)的執(zhí)行順序需要嚴(yán)格控制的話(huà),則不能使用Parallel.For

4 總結(jié)

在計(jì)算機(jī)多核處理器普及的前提下钾麸,合理的使用多線(xiàn)程或者并行能夠顯著提高軟件的運(yùn)行效率更振。當(dāng)然,這一切都是有前提的饭尝。濫用多線(xiàn)程往往會(huì)適得其反肯腕,不僅得不到理想的輸出結(jié)果,甚至?xí)蓴_其他程序的正常運(yùn)行钥平。在明確了自己的需求的前提下实撒,選擇合適的方法才是最重要的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涉瘾,一起剝皮案震驚了整個(gè)濱河市知态,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌立叛,老刑警劉巖负敏,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異秘蛇,居然都是意外死亡其做,警方通過(guò)查閱死者的電腦和手機(jī)顶考,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妖泄,“玉大人村怪,你說(shuō)我怎么就攤上這事「÷” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵柬焕,是天一觀的道長(zhǎng)审残。 經(jīng)常有香客問(wèn)我,道長(zhǎng)斑举,這世上最難降的妖魔是什么搅轿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮富玷,結(jié)果婚禮上璧坟,老公的妹妹穿的比我還像新娘。我一直安慰自己赎懦,他們只是感情好雀鹃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著励两,像睡著了一般黎茎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上当悔,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天傅瞻,我揣著相機(jī)與錄音,去河邊找鬼盲憎。 笑死嗅骄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的饼疙。 我是一名探鬼主播溺森,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窑眯!你這毒婦竟也來(lái)了儿惫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤伸但,失蹤者是張志新(化名)和其女友劉穎肾请,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體更胖,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铛铁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年隔显,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饵逐。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡括眠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出倍权,到底是詐尸還是另有隱情掷豺,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布薄声,位于F島的核電站当船,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏默辨。R本人自食惡果不足惜德频,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缩幸。 院中可真熱鬧壹置,春花似錦、人聲如沸表谊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)爆办。三九已至患亿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間押逼,已是汗流浹背步藕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挑格,地道東北人咙冗。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像漂彤,于是被迫代替她去往敵國(guó)和親雾消。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,101評(píng)論 1 32
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí)挫望,會(huì)觸發(fā)此異常立润。 O...
    我想起個(gè)好名字閱讀 5,317評(píng)論 0 9
  • 這篇文章是我之前翻閱了不少的書(shū)籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方媳板,同時(shí)不同JDK版本的...
    高廣超閱讀 15,603評(píng)論 3 83
  • 第二部分 自動(dòng)內(nèi)存管理機(jī)制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運(yùn)行數(shù)據(jù)區(qū)域 程序計(jì)數(shù)器:當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,164評(píng)論 0 2
  • //Clojure入門(mén)教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語(yǔ)閱讀 3,665評(píng)論 0 7