AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁 > 科技  > 軟件

20行經(jīng)典C代碼,很多人看不明白,你來試一下?

來源: 責(zé)編: 時(shí)間:2023-12-26 09:30:29 395觀看
導(dǎo)讀大家好,我是江南一散人。周末逛知乎時(shí),無意間看到阿里云開發(fā)者官方賬號(hào)的一篇文章中,居然引用了我三年前在今日頭條寫的一篇文章。有些感概,看來還真的在互聯(lián)網(wǎng)上留下了點(diǎn)痕跡。那篇文章,其實(shí)和那篇《改幾行代碼,for循環(huán)耗

大家好,我是江南一散人。周末逛知乎時(shí),無意間看到阿里云開發(fā)者官方賬號(hào)的一篇文章中,居然引用了我三年前在今日頭條寫的一篇文章。有些感概,看來還真的在互聯(lián)網(wǎng)上留下了點(diǎn)痕跡。JAW28資訊網(wǎng)——每日最新資訊28at.com

那篇文章,其實(shí)和那篇《改幾行代碼,for循環(huán)耗時(shí)從3.2秒降到0.3秒!真正看懂的都是牛人!》是相關(guān)的,算是前傳吧,所以在這里發(fā)一下,感興趣的小伙伴不妨圍觀下!JAW28資訊網(wǎng)——每日最新資訊28at.com

全文如下,僅作微調(diào)。JAW28資訊網(wǎng)——每日最新資訊28at.com

引言

昨天發(fā)了一段有趣的代碼,引來很多童鞋圍觀。很多童鞋表示不太明白,于是就有了本文,詳細(xì)解釋下這段代碼的來龍去脈。JAW28資訊網(wǎng)——每日最新資訊28at.com

代碼如下圖所示:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

如果你是第一次看到的話,不妨試一下,看你能得出正確答案嗎?JAW28資訊網(wǎng)——每日最新資訊28at.com

其實(shí),這個(gè)題目還是源自大師之手,我只是做了少許修改。先來聊一下這段歷史淵源吧。JAW28資訊網(wǎng)——每日最新資訊28at.com

注:為了盡量解釋清楚,篇幅有點(diǎn)長,請耐心讀完,相信你會(huì)有收獲的!JAW28資訊網(wǎng)——每日最新資訊28at.com

歷史淵源

1983年11月,一位叫Tom Duff的大牛在編寫串口通信程序時(shí),發(fā)現(xiàn)使用一般的寫法時(shí),性能總是不能讓人滿意。后來,這位老兄憑借深厚的編程功底和精湛的C語言技藝,利用C語言中switch語句的一個(gè)鮮為人知的特性,發(fā)明如了下圖所示的經(jīng)典代碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

結(jié)果,引來無數(shù)吃瓜群眾膜拜。在此之前,還沒有人發(fā)現(xiàn)并利用過C語言的這個(gè)特性,于是他便以自己的名字命名這段代碼,叫做Duff's Device,一般譯為"達(dá)夫設(shè)備"。JAW28資訊網(wǎng)——每日最新資訊28at.com

先看一下大牛的風(fēng)采吧:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

下面講解一下這段代碼。JAW28資訊網(wǎng)——每日最新資訊28at.com

Duff's Device - 達(dá)夫設(shè)備

當(dāng)時(shí),Duff的需求,是把一段起始地址為from,長度為count的數(shù)據(jù),寫入到一個(gè)內(nèi)存映射的I/O(Memory Mapped I/O)寄存器to中。JAW28資訊網(wǎng)——每日最新資訊28at.com

最簡單的實(shí)現(xiàn)

需求很簡單,對吧?很容易想到直接用for或者while循環(huán)就可以解決了,如下圖所示:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

代碼清晰簡潔,很直觀,簡直完美,對吧?JAW28資訊網(wǎng)——每日最新資訊28at.com

Duff卻對此很不滿意,因?yàn)樗X得這種寫法雖然簡單,但太過低效,無法接受。JAW28資訊網(wǎng)——每日最新資訊28at.com

如此簡單的代碼,為何說它性能低下呢?主要有兩個(gè)問題:JAW28資訊網(wǎng)——每日最新資訊28at.com

? "無用"指令太多JAW28資訊網(wǎng)——每日最新資訊28at.com

? 無法充分發(fā)揮CPU的ILP(Instruction-Level Parallelism)技術(shù)JAW28資訊網(wǎng)——每日最新資訊28at.com

我們來分析一下。JAW28資訊網(wǎng)——每日最新資訊28at.com

無用指令太多

所謂無用指令,是指不直接對所期望的結(jié)果產(chǎn)生影響的指令。JAW28資訊網(wǎng)——每日最新資訊28at.com

對于這段代碼,我們期望的結(jié)果就是把數(shù)據(jù)都拷貝到I/O寄存器to中。那么,對于這個(gè)期望的結(jié)果來說,真正有用的代碼,其實(shí)只有中間那一行賦值操作:JAW28資訊網(wǎng)——每日最新資訊28at.com

*to = *from++;

而每次迭代過程中的while (--count > 0)產(chǎn)生的指令,以及每次迭代結(jié)束后的跳轉(zhuǎn)指令,對結(jié)果來說都是無用指令。JAW28資訊網(wǎng)——每日最新資訊28at.com

上面最簡單的實(shí)現(xiàn)中,每次循環(huán)迭代只拷貝一個(gè)字節(jié)數(shù)據(jù)。這就意味著,有多少個(gè)字節(jié)的數(shù)據(jù),就需要執(zhí)行多少次跳轉(zhuǎn)和條件判斷,以及--count的操作。JAW28資訊網(wǎng)——每日最新資訊28at.com

我們看一下匯編代碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

有些童鞋對匯編不太熟悉,我簡單講解一下:JAW28資訊網(wǎng)——每日最新資訊28at.com

? x64上優(yōu)先使用寄存器傳遞,對于send()函數(shù),第一個(gè)參數(shù)to存放在寄存器rdi中,第二個(gè)參數(shù)from存放在rsi中,第三個(gè)參數(shù)count存放在寄存器edx中。JAW28資訊網(wǎng)——每日最新資訊28at.com

? 第2~7行,把三個(gè)參數(shù)分別壓入棧中;JAW28資訊網(wǎng)——每日最新資訊28at.com

? 第9~14行,對應(yīng)C語言的*to = *from++;JAW28資訊網(wǎng)——每日最新資訊28at.com

? 第15~19行,對應(yīng)C語言的while (--count > 0);JAW28資訊網(wǎng)——每日最新資訊28at.com

? 最后幾句,恢復(fù)棧幀并返回JAW28資訊網(wǎng)——每日最新資訊28at.com

所以,第9-19行屬于熱點(diǎn)路徑,也就是主循環(huán)體。第9-14行屬于有效指令,第15-19行對于期望的數(shù)據(jù)結(jié)果來說就是無用指令。JAW28資訊網(wǎng)——每日最新資訊28at.com

我們看到,熱點(diǎn)路徑中,無用指令數(shù)占了整個(gè)熱點(diǎn)路徑指令數(shù)的一半,其開銷也占到整個(gè)函數(shù)的50%!JAW28資訊網(wǎng)——每日最新資訊28at.com

無法充分發(fā)揮ILP技術(shù)優(yōu)勢

現(xiàn)代CPU為了提高指令執(zhí)行的速度和吞吐率,提升系統(tǒng)性能,不僅一直致力于提升CPU的主頻,還實(shí)現(xiàn)了多種ILP(Instruction-Level Parallelism 指令級(jí)并行)技術(shù),如超流水線、超標(biāo)量、亂序執(zhí)行、推測執(zhí)行、分支預(yù)測等。JAW28資訊網(wǎng)——每日最新資訊28at.com

一個(gè)設(shè)計(jì)合理的程序,往往能夠充分利用CPU的這些ILP機(jī)制,以使性能達(dá)到最優(yōu)。JAW28資訊網(wǎng)——每日最新資訊28at.com

但是,在代碼熱點(diǎn)路徑上,無用指令太多,且每個(gè)迭代只執(zhí)行一條*to = *from++,無法充分發(fā)揮ILP的技術(shù)優(yōu)勢。JAW28資訊網(wǎng)——每日最新資訊28at.com

注:這里解釋不夠清楚,詳細(xì)講解請參看文末推薦閱讀的兩篇文章,詳細(xì)介紹了ILP技術(shù)(如超流水線、超標(biāo)量、推測執(zhí)行、分支預(yù)測)。JAW28資訊網(wǎng)——每日最新資訊28at.com

現(xiàn)在,知道上面那個(gè)簡單實(shí)現(xiàn)性能差的原因了,那么如何去優(yōu)化它呢?JAW28資訊網(wǎng)——每日最新資訊28at.com

循環(huán)展開

所謂循環(huán)展開,是通過增加每次迭代內(nèi)數(shù)據(jù)操作的次數(shù),來減小迭代次數(shù),甚至徹底消除循環(huán)迭代的一種優(yōu)化手段。JAW28資訊網(wǎng)——每日最新資訊28at.com

循環(huán)展開,有以下優(yōu)點(diǎn):JAW28資訊網(wǎng)——每日最新資訊28at.com

? 有效減少循環(huán)控制指令。前面說過,這些指令,是對結(jié)果不產(chǎn)生影響的無用指令。減少這些指令,就可以減少這些指令本身執(zhí)行所需的開銷,從而提升整體性能。JAW28資訊網(wǎng)——每日最新資訊28at.com

? 通過合理的展開,可以更加有效地利用指令級(jí)并行ILP(Instruction-Level Parallelism 指令級(jí)并行)技術(shù)。JAW28資訊網(wǎng)——每日最新資訊28at.com

循環(huán)展開是一個(gè)很常用的性能優(yōu)化手段,所有現(xiàn)代編譯器,通過合適的選項(xiàng),都支持循環(huán)展開優(yōu)化。JAW28資訊網(wǎng)——每日最新資訊28at.com

注:關(guān)于循環(huán)展開的詳細(xì)講解,請參看文末推薦閱讀的兩篇文章(如果你還沒看過的話)。JAW28資訊網(wǎng)——每日最新資訊28at.com

有童鞋可能會(huì)好奇,循環(huán)展開到底能提升多少性能呢?我們還是用數(shù)據(jù)說話,看一個(gè)實(shí)例吧。JAW28資訊網(wǎng)——每日最新資訊28at.com

實(shí)例 - 循環(huán)展開對性能的影響

測試環(huán)境:JAW28資訊網(wǎng)——每日最新資訊28at.com

OS:Ubuntu 19.04(Linux Kernel 5.0.0)CPU:Intel(R) Xeon(R) Gold 6130主頻:2.10GHzCache 大小:22MBCache line 大小:64 Bytes

測試代碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

loop1.c和loop2.c做的事情一樣,唯一的區(qū)別是:JAW28資訊網(wǎng)——每日最新資訊28at.com

? loop1.c每次循環(huán)迭代執(zhí)行一次k++JAW28資訊網(wǎng)——每日最新資訊28at.com

  • ? loop2.c每次循環(huán)執(zhí)行8次k++,但是循環(huán)的次數(shù)比loop1.c少了8倍

編譯:JAW28資訊網(wǎng)——每日最新資訊28at.com

gcc loop1.c -o loop1gcc loop2.c -o loop2

測試結(jié)果:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

做同樣的事情,通過循環(huán)展開優(yōu)化,所消耗時(shí)間直接從25.4秒降到了14.7秒!JAW28資訊網(wǎng)——每日最新資訊28at.com

第一次優(yōu)化嘗試

了解了循環(huán)展開對性能提升的好處之后,我們就可以對上面的簡單實(shí)現(xiàn)進(jìn)行第一次優(yōu)化嘗試了。JAW28資訊網(wǎng)——每日最新資訊28at.com

我們先嘗試把每次循環(huán)內(nèi)拷貝字節(jié)的個(gè)數(shù),由1個(gè)提高到到8個(gè),這樣就可以把迭代次數(shù)降低8倍。JAW28資訊網(wǎng)——每日最新資訊28at.com

我們先假設(shè),send()函數(shù)的參數(shù)count總是8的倍數(shù),那么上面的代碼就可以修改為:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

上面的代碼很好理解,就是把原來迭代里的操作復(fù)制了8次,然后把迭代次數(shù)降低到了8倍。JAW28資訊網(wǎng)——每日最新資訊28at.com

但是,我們前面做了一個(gè)假設(shè),就是count是8的倍數(shù)。那如果不是8的整數(shù)倍呢,比如20?那我們可能會(huì)想到這樣的實(shí)現(xiàn):JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

其實(shí),到了這里,相比原始的實(shí)現(xiàn)來說,性能已經(jīng)能提升了不少了。但是,Duff仍然不滿意,他看著第二個(gè)while循環(huán)非常不爽,盡管對整體性能已經(jīng)沒有太大影響了。JAW28資訊網(wǎng)——每日最新資訊28at.com

也許這就是大牛異于常人之處,大牛總是追求極致,總是可以在看似不可能的時(shí)候,再往前走一步。JAW28資訊網(wǎng)——每日最新資訊28at.com

C語言switch-case的一些特性

Duff注意到C語言中switch-case語句的一些特性:JAW28資訊網(wǎng)——每日最新資訊28at.com

? case語句后面的break語句不是必須的。JAW28資訊網(wǎng)——每日最新資訊28at.com

? 在switch語句內(nèi),case標(biāo)號(hào)可以出現(xiàn)在任意的子語句之前,甚至運(yùn)行出現(xiàn)在if、for、while等語句內(nèi)。JAW28資訊網(wǎng)——每日最新資訊28at.com

于是,Duff便利用switch-case的特性,用來處理第一個(gè)while循環(huán)之后仍然剩余的count % 8個(gè)字節(jié)的數(shù)據(jù)。于是便有了這樣的代碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

解釋下這段代碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

我們假設(shè)count = 20,那么:JAW28資訊網(wǎng)——每日最新資訊28at.com

n = (count + 7) / 8 = 27 / 8 = 3count % 8 = 4

所以:JAW28資訊網(wǎng)——每日最新資訊28at.com

  1. 1. switch語句會(huì)落入case 4的標(biāo)簽內(nèi),然后依次執(zhí)行了case 4、3、2、1四條語句。自此之后,其實(shí)就跟switch-case語句再也沒有關(guān)系了。
  2. 2. while語句判斷--n > 0,條件成立,于是跳轉(zhuǎn)到case 0進(jìn)入循環(huán)體執(zhí)行,于是依次執(zhí)行case 0、7、6、5、4、3、2、1一共8條語句。此時(shí)n = 2.
  3. 3. 再次進(jìn)入while語句處判斷--n >0,條件成立,再次跳轉(zhuǎn)到case 0處進(jìn)入循環(huán)體執(zhí)行。此時(shí)n = 1。
  4. 4. 此時(shí),while語句處判斷--n >0,條件失敗,退出循環(huán),函數(shù)結(jié)束。

好了,到這里,大家應(yīng)該理解Duff's Device了吧?還是不清楚的話,可以嘗試單步跟蹤一下,就會(huì)很清晰了。JAW28資訊網(wǎng)——每日最新資訊28at.com

揭曉答案

理解了Duff's Device之后,文章開頭的那個(gè)題目就很好理解了,現(xiàn)在揭曉答案:JAW28資訊網(wǎng)——每日最新資訊28at.com

再看一下源碼:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

編譯運(yùn)行:JAW28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片JAW28資訊網(wǎng)——每日最新資訊28at.com

所以,答案是:20JAW28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-54184-0.html20行經(jīng)典C代碼,很多人看不明白,你來試一下?

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Jedis連接池究竟是何物

下一篇: 一文看懂:函數(shù)式編程為何這么火?

標(biāo)簽:
  • 熱門焦點(diǎn)
  • 2023年Q2用戶偏好榜:12+256G版本成新主流

    3月份的性能榜、性價(jià)比榜和好評榜之后,就要輪到2023年的第二季度偏好榜了,上半年的新機(jī)潮已經(jīng)過去,最明顯的肯定就是大內(nèi)存和存儲(chǔ)的機(jī)型了,另外部分中端機(jī)也取消了屏幕塑料支架
  • 5月iOS設(shè)備性能榜:M1 M2依舊是榜單前五

    和上個(gè)月一樣,沒有新品發(fā)布的iOS設(shè)備性能榜的上榜設(shè)備并沒有什么更替,僅僅只有跑分變化而產(chǎn)生的排名變動(dòng),剛剛開始的蘋果WWDC2023,推出的產(chǎn)品也依舊是新款Mac Pro、新款Mac Stu
  • 5月iOS設(shè)備好評榜:iPhone 14僅排第43?

    來到新的一月,安兔兔的各個(gè)榜單又重新匯總了數(shù)據(jù),像安卓陣營的榜單都有著比較大的變動(dòng),不過iOS由于設(shè)備的更新?lián)Q代并沒有那么快,所以相對來說變化并不大,特別是iOS好評榜,老款設(shè)
  • 十個(gè)簡單但很有用的Python裝飾器

    裝飾器(Decorators)是Python中一種強(qiáng)大而靈活的功能,用于修改或增強(qiáng)函數(shù)或類的行為。裝飾器本質(zhì)上是一個(gè)函數(shù),它接受另一個(gè)函數(shù)或類作為參數(shù),并返回一個(gè)新的函數(shù)或類。它們通常用
  • 微信語音大揭秘:為什么禁止轉(zhuǎn)發(fā)?

    大家好,我是你們的小米。今天,我要和大家聊一個(gè)有趣的話題:為什么微信語音不可以轉(zhuǎn)發(fā)?這是一個(gè)我們經(jīng)常在日常使用中遇到的問題,也是一個(gè)讓很多人好奇的問題。讓我們一起來揭開這
  • 一文掌握 Golang 模糊測試(Fuzz Testing)

    模糊測試(Fuzz Testing)模糊測試(Fuzz Testing)是通過向目標(biāo)系統(tǒng)提供非預(yù)期的輸入并監(jiān)視異常結(jié)果來發(fā)現(xiàn)軟件漏洞的方法。可以用來發(fā)現(xiàn)應(yīng)用程序、操作系統(tǒng)和網(wǎng)絡(luò)協(xié)議等中的漏洞或
  • 共享單車的故事講到哪了?

    來源丨海克財(cái)經(jīng)與共享充電寶相差不多,共享單車已很久沒有被國內(nèi)熱點(diǎn)新聞關(guān)照到了。除了一再漲價(jià)和用戶直呼用不起了。近日多家媒體再發(fā)報(bào)道稱,成都、天津、鄭州等地多個(gè)共享單
  • 超級(jí)標(biāo)準(zhǔn)版旗艦!iQOO 11S全球首發(fā)iQOO超算獨(dú)顯芯片

    上半年已接近尾聲,截至目前各大品牌旗下的頂級(jí)旗艦都已悉數(shù)亮相,而下半年即將推出的頂級(jí)旗艦已經(jīng)成為了數(shù)碼圈爆料的主流,其中就包括全新的iQOO 11S系
  • Android 14發(fā)布:首批適配機(jī)型公布

    5月11日消息,谷歌在今天凌晨舉行了I/O大會(huì),本次發(fā)布會(huì)谷歌帶來了自家的AI語言模型PaLM 2、谷歌Pixel Fold折疊屏、谷歌Pixel 7a手機(jī),同時(shí)發(fā)布了Androi
Top