欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

go語(yǔ)言可視化設(shè)計(jì) Go設(shè)計(jì)模式

Go語(yǔ)言的優(yōu)勢(shì)有哪些

1. 部署簡(jiǎn)單

創(chuàng)新互聯(lián)總部坐落于成都市區(qū),致力網(wǎng)站建設(shè)服務(wù)有成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃、網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站維護(hù)、公眾號(hào)搭建、微信小程序、軟件開(kāi)發(fā)等為企業(yè)提供一整套的信息化建設(shè)解決方案。創(chuàng)造真正意義上的網(wǎng)站建設(shè),為互聯(lián)網(wǎng)品牌在互動(dòng)行銷(xiāo)領(lǐng)域創(chuàng)造價(jià)值而不懈努力!

Go

編譯生成的是一個(gè)靜態(tài)可執(zhí)行文件,除了glibc外沒(méi)有其他外部依賴(lài)。這讓部署變得異常方便:目標(biāo)機(jī)器上只需要一個(gè)基礎(chǔ)的系統(tǒng)和必要的管理、監(jiān)控工具,完全不需要操心應(yīng)用所需的各種包、庫(kù)的依賴(lài)關(guān)系,大大減輕了維護(hù)的負(fù)擔(dān)。

2. 并發(fā)性好

Goroutine和channel使得編寫(xiě)高并發(fā)的服務(wù)端軟件變得相當(dāng)容易,很多情況下完全不需要考慮鎖機(jī)制以及由此帶來(lái)的各種問(wèn)題。單個(gè)Go應(yīng)用也能有效的利用多個(gè)CPU核,并行執(zhí)行的性能好。

3. 良好的語(yǔ)言設(shè)計(jì)

從學(xué)術(shù)的角度講Go語(yǔ)言其實(shí)非常平庸,不支持許多高級(jí)的語(yǔ)言特性;但從工程的角度講,Go的設(shè)計(jì)是非常優(yōu)秀的:規(guī)范足夠簡(jiǎn)單靈活,有其他語(yǔ)言基礎(chǔ)的程序員都能迅速上手。更重要的是

Go 自帶完善的工具鏈,大大提高了團(tuán)隊(duì)協(xié)作的一致性。

4. 執(zhí)行性能好

雖然不如 C 和 Java,但相比于其他編程語(yǔ)言,其執(zhí)行性能還是很好的,適合編寫(xiě)一些瓶頸業(yè)務(wù),內(nèi)存占用也非常省。

最難的開(kāi)發(fā)語(yǔ)言

第十名、R語(yǔ)言

R語(yǔ)言,一種自由軟件編程語(yǔ)言與操作環(huán)境,主要用于統(tǒng)計(jì)分析、繪圖、數(shù)據(jù)挖掘。R基于S語(yǔ)言的一個(gè)GNU計(jì)劃項(xiàng)目,所以也可以當(dāng)作S語(yǔ)言的一種實(shí)現(xiàn),通常用S語(yǔ)言編寫(xiě)的代碼都可以不作修改的在R環(huán)境下運(yùn)行。R的語(yǔ)法是來(lái)自Scheme。

提名詞

R語(yǔ)言作者,George Ross Ihaka:在奧克蘭大學(xué)統(tǒng)計(jì)系任副教授,是R語(yǔ)言的最初作者。

2

/10

第九名、Python

頒獎(jiǎng)詞

Python是一種廣泛使用的高級(jí)編程語(yǔ)言,屬于通用型編程語(yǔ)言。作為一種解釋型語(yǔ)言,Python的設(shè)計(jì)哲學(xué)強(qiáng)調(diào)代碼的可讀性和簡(jiǎn)潔的語(yǔ)法。相比于C++或Java,Python讓開(kāi)發(fā)者能夠用更少的代碼表達(dá)想法。不管是小型還是大型程序,該語(yǔ)言都試圖讓程序的結(jié)構(gòu)清晰明了。

提名詞

Python語(yǔ)言作者,Guido van Rossum:生于荷蘭哈勒姆,計(jì)算機(jī)程序員,為Python程序設(shè)計(jì)語(yǔ)言的最初設(shè)計(jì)者及主要架構(gòu)師。

3

/10

第八名、C語(yǔ)言

頒獎(jiǎng)詞

C是一種通用的編程語(yǔ)言,廣泛用于系統(tǒng)軟件與應(yīng)用軟件的開(kāi)發(fā)。C語(yǔ)言具有高效、靈活、功能豐富、表達(dá)力強(qiáng)和較高的可移植性等特點(diǎn)。C語(yǔ)言編譯器普遍存在于各種不同的操作系統(tǒng)中,例如Microsoft Windows、macOS、Linux、Unix等。C語(yǔ)言的設(shè)計(jì)影響了眾多后來(lái)的編程語(yǔ)言,例如C++、Objective-C、Java、C#等。

提名詞

C語(yǔ)言作者,Dennis MacAlistair Ritchie:美國(guó)計(jì)算機(jī)科學(xué)家。黑客圈子通常稱(chēng)他為“dmr”。他是C語(yǔ)言的創(chuàng)造者、Unix操作系統(tǒng)的關(guān)鍵開(kāi)發(fā)者,對(duì)計(jì)算機(jī)領(lǐng)域產(chǎn)生了深遠(yuǎn)影響,并與肯·湯普遜同為1983年圖靈獎(jiǎng)得主。

4

/10

第七名、Go

頒獎(jiǎng)詞

Go(又稱(chēng)Golang)是Google開(kāi)發(fā)的一種靜態(tài)強(qiáng)類(lèi)型、編譯型、并發(fā)型,并具有垃圾回收功能的編程語(yǔ)言。Go的語(yǔ)法接近C語(yǔ)言,但對(duì)于變量的聲明有所不同。Go支持垃圾回收功能。

提名詞

Go語(yǔ)言作者,Robert C. Pike:來(lái)自加拿大的程序員,曾經(jīng)加入貝爾實(shí)驗(yàn)室,為 UNIX小組的成員。他與肯·湯普遜共同開(kāi)發(fā)了UTF-8。目前為 google的工程師,參與編程語(yǔ)言 Go與Sawzall的研發(fā)工作。

5

/10

第六名、JavaScript

頒獎(jiǎng)詞

JavaScript,通??s寫(xiě)為JS,是一種高級(jí)的,解釋執(zhí)行的編程語(yǔ)言。JavaScript是一門(mén)基于原型、函數(shù)先行的語(yǔ)言,是一門(mén)多范式的語(yǔ)言,它支持面向?qū)ο缶幊?,命令式編程,以及函?shù)式編程。它已經(jīng)由ECMA(歐洲計(jì)算機(jī)制造商協(xié)會(huì))通過(guò)ECMAScript實(shí)現(xiàn)語(yǔ)言的標(biāo)準(zhǔn)化。它被世界上的絕大多數(shù)網(wǎng)站所使用,也被世界主流瀏覽器(Chrome、IE、Firefox、Safari、Opera)支持。

提名詞

JavaScript語(yǔ)言作者,Brendan Eich:美國(guó)程序員與企業(yè)家,JavaScript主要?jiǎng)?chuàng)造者與架構(gòu)師,曾任Mozilla公司的首席技術(shù)官,并曾短暫擔(dān)任首席執(zhí)行官。

6

/10

第五名、Objective-C

頒獎(jiǎng)詞

Objective-C是一種通用、高級(jí)、面向?qū)ο蟮木幊陶Z(yǔ)言。它擴(kuò)展了標(biāo)準(zhǔn)的ANSI C編程語(yǔ)言,將Smalltalk式的消息傳遞機(jī)制加入到ANSI C中。目前主要支持的編譯器有GCC和Clang(采用LLVM作為后端)。

提名詞

Objective-C作者,Brad Cox:美國(guó)計(jì)算機(jī)科學(xué)家。于傅爾曼大學(xué)主修化學(xué)與數(shù)學(xué),于芝加哥大學(xué)取得數(shù)學(xué)生物學(xué)博士學(xué)位。Objective-C主要作者。

7

/10

第四名、PHP

頒獎(jiǎng)詞

PHP(全稱(chēng):PHP:Hypertext Preprocessor,即“PHP:超文本預(yù)處理器”)是開(kāi)源的通用計(jì)算機(jī)腳本語(yǔ)言,尤其適用于網(wǎng)絡(luò)開(kāi)發(fā)并可嵌入HTML中使用。PHP的語(yǔ)法借鑒吸收C語(yǔ)言、Java和Perl等流行計(jì)算機(jī)語(yǔ)言的特點(diǎn),易于一般程序員學(xué)習(xí)。PHP的主要目標(biāo)是允許網(wǎng)絡(luò)開(kāi)發(fā)人員快速編寫(xiě)動(dòng)態(tài)頁(yè)面,但PHP也被用于其他很多領(lǐng)域。

提名詞

PHP語(yǔ)言作者,Rasmus Lerdorf:出生于格陵蘭島凱凱塔蘇瓦克,是一個(gè)丹麥程序員,他擁有加拿大國(guó)籍。他也是編程語(yǔ)言PHP的創(chuàng)始人,其中PHP的頭兩個(gè)版本是由他編寫(xiě)的,后來(lái)他也參與PHP后續(xù)版本的開(kāi)發(fā)。

8

/10

第三名、Java

頒獎(jiǎng)詞

Java是一種廣泛使用的計(jì)算機(jī)編程語(yǔ)言,擁有跨平臺(tái)、面向?qū)ο?、泛型編程的特性,廣泛應(yīng)用于企業(yè)級(jí)Web應(yīng)用開(kāi)發(fā)和移動(dòng)應(yīng)用開(kāi)發(fā)。Java編程語(yǔ)言是個(gè)簡(jiǎn)單、面向?qū)ο?、分布式、解釋性、健壯、安全與系統(tǒng)無(wú)關(guān)、可移植、高性能、多線(xiàn)程和動(dòng)態(tài)的語(yǔ)言。

提名詞

Java語(yǔ)言作者,James Gosling:出生于加拿大,軟件專(zhuān)家,Java編程語(yǔ)言的共同創(chuàng)始人之一,一般公認(rèn)他為“Java之父”。

9

/10

第二名、C++

頒獎(jiǎng)詞

C++是一種使用廣泛的計(jì)算機(jī)程序設(shè)計(jì)語(yǔ)言。它是一種通用程序設(shè)計(jì)語(yǔ)言,支持多重編程模式,例如過(guò)程化程序設(shè)計(jì)、數(shù)據(jù)抽象、面向?qū)ο蟪绦蛟O(shè)計(jì)、泛型程序設(shè)計(jì)和設(shè)計(jì)模式等。

提名詞

C++語(yǔ)言作者,Bjarne Stroustrup:生于丹麥奧胡斯郡,計(jì)算機(jī)科學(xué)家。他以創(chuàng)造C++編程語(yǔ)言而聞名,被稱(chēng)為“C++之父”。

10

/10

第一名、Visual Basic .NET

頒獎(jiǎng)詞

Visual Basic .NET(VB.NET)是.NET Framework框架下的一種多重編程范式高級(jí)語(yǔ)言。Visual Basic .NET屬Basic系語(yǔ)言,其語(yǔ)法特點(diǎn)是以極具親和力的英文單詞為基礎(chǔ)標(biāo)識(shí),以及與自然語(yǔ)言極其相近的邏輯表達(dá),有時(shí)候你會(huì)覺(jué)得寫(xiě)VB.NET代碼就好像在寫(xiě)英文句子一樣,從這個(gè)角度來(lái)說(shuō),VB.NET似乎是最高級(jí)的一門(mén)編程語(yǔ)言,當(dāng)然在Basic系語(yǔ)言中VB.NET也確實(shí)是迄今為止最強(qiáng)大的一門(mén)編程語(yǔ)言。

提名詞

Visual Basic .NET作者,Alan Cooper:交互設(shè)計(jì)的提倡者。庫(kù)珀有些時(shí)候被叫做 Visual Basic 之父,雖然大多數(shù)的工作是由微軟的內(nèi)部開(kāi)發(fā)團(tuán)隊(duì)完成的,但是對(duì)于Windows可視化設(shè)計(jì)工具的創(chuàng)意是來(lái)源于庫(kù)珀的。

徹底理解Golang Map

本文目錄如下,閱讀本文后,將一網(wǎng)打盡下面Golang Map相關(guān)面試題

Go中的map是一個(gè)指針,占用8個(gè)字節(jié),指向hmap結(jié)構(gòu)體; 源碼 src/runtime/map.go 中可以看到map的底層結(jié)構(gòu)

每個(gè)map的底層結(jié)構(gòu)是hmap,hmap包含若干個(gè)結(jié)構(gòu)為bmap的bucket數(shù)組。每個(gè)bucket底層都采用鏈表結(jié)構(gòu)。接下來(lái),我們來(lái)詳細(xì)看下map的結(jié)構(gòu)

bmap 就是我們常說(shuō)的“桶”,一個(gè)桶里面會(huì)最多裝 8 個(gè) key,這些 key 之所以會(huì)落入同一個(gè)桶,是因?yàn)樗鼈兘?jīng)過(guò)哈希計(jì)算后,哈希結(jié)果是“一類(lèi)”的,關(guān)于key的定位我們?cè)趍ap的查詢(xún)和插入中詳細(xì)說(shuō)明。在桶內(nèi),又會(huì)根據(jù) key 計(jì)算出來(lái)的 hash 值的高 8 位來(lái)決定 key 到底落入桶內(nèi)的哪個(gè)位置(一個(gè)桶內(nèi)最多有8個(gè)位置)。

bucket內(nèi)存數(shù)據(jù)結(jié)構(gòu)可視化如下:

注意到 key 和 value 是各自放在一起的,并不是 key/value/key/value/... 這樣的形式。源碼里說(shuō)明這樣的好處是在某些情況下可以省略掉 padding字段,節(jié)省內(nèi)存空間。

當(dāng) map 的 key 和 value 都不是指針,并且 size 都小于 128 字節(jié)的情況下,會(huì)把 bmap 標(biāo)記為不含指針,這樣可以避免 gc 時(shí)掃描整個(gè) hmap。但是,我們看 bmap 其實(shí)有一個(gè) overflow 的字段,是指針類(lèi)型的,破壞了 bmap 不含指針的設(shè)想,這時(shí)會(huì)把 overflow 移動(dòng)到 extra 字段來(lái)。

map是個(gè)指針,底層指向hmap,所以是個(gè)引用類(lèi)型

golang 有三個(gè)常用的高級(jí)類(lèi)型 slice 、map、channel, 它們都是 引用類(lèi)型 ,當(dāng)引用類(lèi)型作為函數(shù)參數(shù)時(shí),可能會(huì)修改原內(nèi)容數(shù)據(jù)。

golang 中沒(méi)有引用傳遞,只有值和指針傳遞。所以 map 作為函數(shù)實(shí)參傳遞時(shí)本質(zhì)上也是值傳遞,只不過(guò)因?yàn)?map 底層數(shù)據(jù)結(jié)構(gòu)是通過(guò)指針指向?qū)嶋H的元素存儲(chǔ)空間,在被調(diào)函數(shù)中修改 map,對(duì)調(diào)用者同樣可見(jiàn),所以 map 作為函數(shù)實(shí)參傳遞時(shí)表現(xiàn)出了引用傳遞的效果。

因此,傳遞 map 時(shí),如果想修改map的內(nèi)容而不是map本身,函數(shù)形參無(wú)需使用指針

map 底層數(shù)據(jù)結(jié)構(gòu)是通過(guò)指針指向?qū)嶋H的元素 存儲(chǔ)空間 ,這種情況下,對(duì)其中一個(gè)map的更改,會(huì)影響到其他map

map 在沒(méi)有被修改的情況下,使用 range 多次遍歷 map 時(shí)輸出的 key 和 value 的順序可能不同。這是 Go 語(yǔ)言的設(shè)計(jì)者們有意為之,在每次 range 時(shí)的順序被隨機(jī)化,旨在提示開(kāi)發(fā)者們,Go 底層實(shí)現(xiàn)并不保證 map 遍歷順序穩(wěn)定,請(qǐng)大家不要依賴(lài) range 遍歷結(jié)果順序。

map 本身是無(wú)序的,且遍歷時(shí)順序還會(huì)被隨機(jī)化,如果想順序遍歷 map,需要對(duì) map key 先排序,再按照 key 的順序遍歷 map。

map默認(rèn)是并發(fā)不安全的,原因如下:

Go 官方在經(jīng)過(guò)了長(zhǎng)時(shí)間的討論后,認(rèn)為 Go map 更應(yīng)適配典型使用場(chǎng)景(不需要從多個(gè) goroutine 中進(jìn)行安全訪(fǎng)問(wèn)),而不是為了小部分情況(并發(fā)訪(fǎng)問(wèn)),導(dǎo)致大部分程序付出加鎖代價(jià)(性能),決定了不支持。

場(chǎng)景: 2個(gè)協(xié)程同時(shí)讀和寫(xiě),以下程序會(huì)出現(xiàn)致命錯(cuò)誤:fatal error: concurrent map writes

如果想實(shí)現(xiàn)map線(xiàn)程安全,有兩種方式:

方式一:使用讀寫(xiě)鎖 map + sync.RWMutex

方式二:使用golang提供的 sync.Map

sync.map是用讀寫(xiě)分離實(shí)現(xiàn)的,其思想是空間換時(shí)間。和map+RWLock的實(shí)現(xiàn)方式相比,它做了一些優(yōu)化:可以無(wú)鎖訪(fǎng)問(wèn)read map,而且會(huì)優(yōu)先操作read map,倘若只操作read map就可以滿(mǎn)足要求(增刪改查遍歷),那就不用去操作write map(它的讀寫(xiě)都要加鎖),所以在某些特定場(chǎng)景中它發(fā)生鎖競(jìng)爭(zhēng)的頻率會(huì)遠(yuǎn)遠(yuǎn)小于map+RWLock的實(shí)現(xiàn)方式。

golang中map是一個(gè)kv對(duì)集合。底層使用hash table,用鏈表來(lái)解決沖突 ,出現(xiàn)沖突時(shí),不是每一個(gè)key都申請(qǐng)一個(gè)結(jié)構(gòu)通過(guò)鏈表串起來(lái),而是以bmap為最小粒度掛載,一個(gè)bmap可以放8個(gè)kv。在哈希函數(shù)的選擇上,會(huì)在程序啟動(dòng)時(shí),檢測(cè) cpu 是否支持 aes,如果支持,則使用 aes hash,否則使用 memhash。

map有3鐘初始化方式,一般通過(guò)make方式創(chuàng)建

map的創(chuàng)建通過(guò)生成匯編碼可以知道,make創(chuàng)建map時(shí)調(diào)用的底層函數(shù)是 runtime.makemap 。如果你的map初始容量小于等于8會(huì)發(fā)現(xiàn)走的是 runtime.fastrand 是因?yàn)槿萘啃∮?時(shí)不需要生成多個(gè)桶,一個(gè)桶的容量就可以滿(mǎn)足

makemap函數(shù)會(huì)通過(guò) fastrand 創(chuàng)建一個(gè)隨機(jī)的哈希種子,然后根據(jù)傳入的 hint 計(jì)算出需要的最小需要的桶的數(shù)量,最后再使用 makeBucketArray 創(chuàng)建用于保存桶的數(shù)組,這個(gè)方法其實(shí)就是根據(jù)傳入的 B 計(jì)算出的需要?jiǎng)?chuàng)建的桶數(shù)量在內(nèi)存中分配一片連續(xù)的空間用于存儲(chǔ)數(shù)據(jù),在創(chuàng)建桶的過(guò)程中還會(huì)額外創(chuàng)建一些用于保存溢出數(shù)據(jù)的桶,數(shù)量是 2^(B-4) 個(gè)。初始化完成返回hmap指針。

找到一個(gè) B,使得 map 的裝載因子在正常范圍內(nèi)

Go 語(yǔ)言中讀取 map 有兩種語(yǔ)法:帶 comma 和 不帶 comma。當(dāng)要查詢(xún)的 key 不在 map 里,帶 comma 的用法會(huì)返回一個(gè) bool 型變量提示 key 是否在 map 中;而不帶 comma 的語(yǔ)句則會(huì)返回一個(gè) value 類(lèi)型的零值。如果 value 是 int 型就會(huì)返回 0,如果 value 是 string 類(lèi)型,就會(huì)返回空字符串。

map的查找通過(guò)生成匯編碼可以知道,根據(jù) key 的不同類(lèi)型,編譯器會(huì)將查找函數(shù)用更具體的函數(shù)替換,以?xún)?yōu)化效率:

函數(shù)首先會(huì)檢查 map 的標(biāo)志位 flags。如果 flags 的寫(xiě)標(biāo)志位此時(shí)被置 1 了,說(shuō)明有其他協(xié)程在執(zhí)行“寫(xiě)”操作,進(jìn)而導(dǎo)致程序 panic。這也說(shuō)明了 map 對(duì)協(xié)程是不安全的。

key經(jīng)過(guò)哈希函數(shù)計(jì)算后,得到的哈希值如下(主流64位機(jī)下共 64 個(gè) bit 位):

m: 桶的個(gè)數(shù)

從buckets 通過(guò) hash m 得到對(duì)應(yīng)的bucket,如果bucket正在擴(kuò)容,并且沒(méi)有擴(kuò)容完成,則從oldbuckets得到對(duì)應(yīng)的bucket

計(jì)算hash所在桶編號(hào):

用上一步哈希值最后的 5 個(gè) bit 位,也就是 01010 ,值為 10,也就是 10 號(hào)桶(范圍是0~31號(hào)桶)

計(jì)算hash所在的槽位:

用上一步哈希值哈希值的高8個(gè)bit 位,也就是 10010111 ,轉(zhuǎn)化為十進(jìn)制,也就是151,在 10 號(hào) bucket 中尋找** tophash 值(HOB hash)為 151* 的 槽位**,即為key所在位置,找到了 2 號(hào)槽位,這樣整個(gè)查找過(guò)程就結(jié)束了。

如果在 bucket 中沒(méi)找到,并且 overflow 不為空,還要繼續(xù)去 overflow bucket 中尋找,直到找到或是所有的 key 槽位都找遍了,包括所有的 overflow bucket。

通過(guò)上面找到了對(duì)應(yīng)的槽位,這里我們?cè)僭敿?xì)分析下key/value值是如何獲取的:

bucket 里 key 的起始地址就是 unsafe.Pointer(b)+dataOffset。第 i 個(gè) key 的地址就要在此基礎(chǔ)上跨過(guò) i 個(gè) key 的大小;而我們又知道,value 的地址是在所有 key 之后,因此第 i 個(gè) value 的地址還需要加上所有 key 的偏移。

通過(guò)匯編語(yǔ)言可以看到,向 map 中插入或者修改 key,最終調(diào)用的是 mapassign 函數(shù)。

實(shí)際上插入或修改 key 的語(yǔ)法是一樣的,只不過(guò)前者操作的 key 在 map 中不存在,而后者操作的 key 存在 map 中。

mapassign 有一個(gè)系列的函數(shù),根據(jù) key 類(lèi)型的不同,編譯器會(huì)將其優(yōu)化為相應(yīng)的“快速函數(shù)”。

我們只用研究最一般的賦值函數(shù) mapassign 。

map的賦值會(huì)附帶著map的擴(kuò)容和遷移,map的擴(kuò)容只是將底層數(shù)組擴(kuò)大了一倍,并沒(méi)有進(jìn)行數(shù)據(jù)的轉(zhuǎn)移,數(shù)據(jù)的轉(zhuǎn)移是在擴(kuò)容后逐步進(jìn)行的,在遷移的過(guò)程中每進(jìn)行一次賦值(access或者delete)會(huì)至少做一次遷移工作。

1.判斷map是否為nil

每一次進(jìn)行賦值/刪除操作時(shí),只要oldbuckets != nil 則認(rèn)為正在擴(kuò)容,會(huì)做一次遷移工作,下面會(huì)詳細(xì)說(shuō)下遷移過(guò)程

根據(jù)上面查找過(guò)程,查找key所在位置,如果找到則更新,沒(méi)找到則找空位插入即可

經(jīng)過(guò)前面迭代尋找動(dòng)作,若沒(méi)有找到可插入的位置,意味著需要擴(kuò)容進(jìn)行插入,下面會(huì)詳細(xì)說(shuō)下擴(kuò)容過(guò)程

通過(guò)匯編語(yǔ)言可以看到,向 map 中刪除 key,最終調(diào)用的是 mapdelete 函數(shù)

刪除的邏輯相對(duì)比較簡(jiǎn)單,大多函數(shù)在賦值操作中已經(jīng)用到過(guò),核心還是找到 key 的具體位置。尋找過(guò)程都是類(lèi)似的,在 bucket 中挨個(gè) cell 尋找。找到對(duì)應(yīng)位置后,對(duì) key 或者 value 進(jìn)行“清零”操作,將 count 值減 1,將對(duì)應(yīng)位置的 tophash 值置成 Empty

再來(lái)說(shuō)觸發(fā) map 擴(kuò)容的時(shí)機(jī):在向 map 插入新 key 的時(shí)候,會(huì)進(jìn)行條件檢測(cè),符合下面這 2 個(gè)條件,就會(huì)觸發(fā)擴(kuò)容:

1、裝載因子超過(guò)閾值

源碼里定義的閾值是 6.5 (loadFactorNum/loadFactorDen),是經(jīng)過(guò)測(cè)試后取出的一個(gè)比較合理的因子

我們知道,每個(gè) bucket 有 8 個(gè)空位,在沒(méi)有溢出,且所有的桶都裝滿(mǎn)了的情況下,裝載因子算出來(lái)的結(jié)果是 8。因此當(dāng)裝載因子超過(guò) 6.5 時(shí),表明很多 bucket 都快要裝滿(mǎn)了,查找效率和插入效率都變低了。在這個(gè)時(shí)候進(jìn)行擴(kuò)容是有必要的。

對(duì)于條件 1,元素太多,而 bucket 數(shù)量太少,很簡(jiǎn)單:將 B 加 1,bucket 最大數(shù)量( 2^B )直接變成原來(lái) bucket 數(shù)量的 2 倍。于是,就有新老 bucket 了。注意,這時(shí)候元素都在老 bucket 里,還沒(méi)遷移到新的 bucket 來(lái)。新 bucket 只是最大數(shù)量變?yōu)樵瓉?lái)最大數(shù)量的 2 倍( 2^B * 2 ) 。

2、overflow 的 bucket 數(shù)量過(guò)多

在裝載因子比較小的情況下,這時(shí)候 map 的查找和插入效率也很低,而第 1 點(diǎn)識(shí)別不出來(lái)這種情況。表面現(xiàn)象就是計(jì)算裝載因子的分子比較小,即 map 里元素總數(shù)少,但是 bucket 數(shù)量多(真實(shí)分配的 bucket 數(shù)量多,包括大量的 overflow bucket)

不難想像造成這種情況的原因:不停地插入、刪除元素。先插入很多元素,導(dǎo)致創(chuàng)建了很多 bucket,但是裝載因子達(dá)不到第 1 點(diǎn)的臨界值,未觸發(fā)擴(kuò)容來(lái)緩解這種情況。之后,刪除元素降低元素總數(shù)量,再插入很多元素,導(dǎo)致創(chuàng)建很多的 overflow bucket,但就是不會(huì)觸發(fā)第 1 點(diǎn)的規(guī)定,你能拿我怎么辦?overflow bucket 數(shù)量太多,導(dǎo)致 key 會(huì)很分散,查找插入效率低得嚇人,因此出臺(tái)第 2 點(diǎn)規(guī)定。這就像是一座空城,房子很多,但是住戶(hù)很少,都分散了,找起人來(lái)很困難

對(duì)于條件 2,其實(shí)元素沒(méi)那么多,但是 overflow bucket 數(shù)特別多,說(shuō)明很多 bucket 都沒(méi)裝滿(mǎn)。解決辦法就是開(kāi)辟一個(gè)新 bucket 空間,將老 bucket 中的元素移動(dòng)到新 bucket,使得同一個(gè) bucket 中的 key 排列地更緊密。這樣,原來(lái),在 overflow bucket 中的 key 可以移動(dòng)到 bucket 中來(lái)。結(jié)果是節(jié)省空間,提高 bucket 利用率,map 的查找和插入效率自然就會(huì)提升。

由于 map 擴(kuò)容需要將原有的 key/value 重新搬遷到新的內(nèi)存地址,如果有大量的 key/value 需要搬遷,會(huì)非常影響性能。因此 Go map 的擴(kuò)容采取了一種稱(chēng)為“漸進(jìn)式”的方式,原有的 key 并不會(huì)一次性搬遷完畢,每次最多只會(huì)搬遷 2 個(gè) bucket。

上面說(shuō)的 hashGrow() 函數(shù)實(shí)際上并沒(méi)有真正地“搬遷”,它只是分配好了新的 buckets,并將老的 buckets 掛到了 oldbuckets 字段上。真正搬遷 buckets 的動(dòng)作在 growWork() 函數(shù)中,而調(diào)用 growWork() 函數(shù)的動(dòng)作是在 mapassign 和 mapdelete 函數(shù)中。也就是插入或修改、刪除 key 的時(shí)候,都會(huì)嘗試進(jìn)行搬遷 buckets 的工作。先檢查 oldbuckets 是否搬遷完畢,具體來(lái)說(shuō)就是檢查 oldbuckets 是否為 nil。

如果未遷移完畢,賦值/刪除的時(shí)候,擴(kuò)容完畢后(預(yù)分配內(nèi)存),不會(huì)馬上就進(jìn)行遷移。而是采取 增量擴(kuò)容 的方式,當(dāng)有訪(fǎng)問(wèn)到具體 bukcet 時(shí),才會(huì)逐漸的進(jìn)行遷移(將 oldbucket 遷移到 bucket)

nevacuate 標(biāo)識(shí)的是當(dāng)前的進(jìn)度,如果都搬遷完,應(yīng)該和2^B的長(zhǎng)度是一樣的

在evacuate 方法實(shí)現(xiàn)是把這個(gè)位置對(duì)應(yīng)的bucket,以及其沖突鏈上的數(shù)據(jù)都轉(zhuǎn)移到新的buckets上。

轉(zhuǎn)移的判斷直接通過(guò)tophash 就可以,判斷tophash中第一個(gè)hash值即可

遍歷的過(guò)程,就是按順序遍歷 bucket,同時(shí)按順序遍歷 bucket 中的 key。

map遍歷是無(wú)序的,如果想實(shí)現(xiàn)有序遍歷,可以先對(duì)key進(jìn)行排序

為什么遍歷 map 是無(wú)序的?

如果發(fā)生過(guò)遷移,key 的位置發(fā)生了重大的變化,有些 key 飛上高枝,有些 key 則原地不動(dòng)。這樣,遍歷 map 的結(jié)果就不可能按原來(lái)的順序了。

如果就一個(gè)寫(xiě)死的 map,不會(huì)向 map 進(jìn)行插入刪除的操作,按理說(shuō)每次遍歷這樣的 map 都會(huì)返回一個(gè)固定順序的 key/value 序列吧。但是 Go 杜絕了這種做法,因?yàn)檫@樣會(huì)給新手程序員帶來(lái)誤解,以為這是一定會(huì)發(fā)生的事情,在某些情況下,可能會(huì)釀成大錯(cuò)。

Go 做得更絕,當(dāng)我們?cè)诒闅v map 時(shí),并不是固定地從 0 號(hào) bucket 開(kāi)始遍歷,每次都是從一個(gè)**隨機(jī)值序號(hào)的 bucket 開(kāi)始遍歷,并且是從這個(gè) bucket 的一個(gè) 隨機(jī)序號(hào)的 cell **開(kāi)始遍歷。這樣,即使你是一個(gè)寫(xiě)死的 map,僅僅只是遍歷它,也不太可能會(huì)返回一個(gè)固定序列的 key/value 對(duì)了。

Go語(yǔ)言設(shè)計(jì)與實(shí)現(xiàn)(上)

基本設(shè)計(jì)思路:

類(lèi)型轉(zhuǎn)換、類(lèi)型斷言、動(dòng)態(tài)派發(fā)。iface,eface。

反射對(duì)象具有的方法:

編譯優(yōu)化:

內(nèi)部實(shí)現(xiàn):

實(shí)現(xiàn) Context 接口有以下幾個(gè)類(lèi)型(空實(shí)現(xiàn)就忽略了):

互斥鎖的控制邏輯:

設(shè)計(jì)思路:

(以上為寫(xiě)被讀阻塞,下面是讀被寫(xiě)阻塞)

總結(jié),讀寫(xiě)鎖的設(shè)計(jì)還是非常巧妙的:

設(shè)計(jì)思路:

WaitGroup 有三個(gè)暴露的函數(shù):

部件:

設(shè)計(jì)思路:

結(jié)構(gòu):

Once 只暴露了一個(gè)方法:

實(shí)現(xiàn):

三個(gè)關(guān)鍵點(diǎn):

細(xì)節(jié):

讓多協(xié)程任務(wù)的開(kāi)始執(zhí)行時(shí)間可控(按順序或歸一)。(Context 是控制結(jié)束時(shí)間)

設(shè)計(jì)思路: 通過(guò)一個(gè)鎖和內(nèi)置的 notifyList 隊(duì)列實(shí)現(xiàn),Wait() 會(huì)生成票據(jù),并將等待協(xié)程信息加入鏈表中,等待控制協(xié)程中發(fā)送信號(hào)通知一個(gè)(Signal())或所有(Boardcast())等待者(內(nèi)部實(shí)現(xiàn)是通過(guò)票據(jù)通知的)來(lái)控制協(xié)程解除阻塞。

暴露四個(gè)函數(shù):

實(shí)現(xiàn)細(xì)節(jié):

部件:

包: golang.org/x/sync/errgroup

作用:開(kāi)啟 func() error 函數(shù)簽名的協(xié)程,在同 Group 下協(xié)程并發(fā)執(zhí)行過(guò)程并收集首次 err 錯(cuò)誤。通過(guò) Context 的傳入,還可以控制在首次 err 出現(xiàn)時(shí)就終止組內(nèi)各協(xié)程。

設(shè)計(jì)思路:

結(jié)構(gòu):

暴露的方法:

實(shí)現(xiàn)細(xì)節(jié):

注意問(wèn)題:

包: "golang.org/x/sync/semaphore"

作用:排隊(duì)借資源(如錢(qián),有借有還)的一種場(chǎng)景。此包相當(dāng)于對(duì)底層信號(hào)量的一種暴露。

設(shè)計(jì)思路:有一定數(shù)量的資源 Weight,每一個(gè) waiter 攜帶一個(gè) channel 和要借的數(shù)量 n。通過(guò)隊(duì)列排隊(duì)執(zhí)行借貸。

結(jié)構(gòu):

暴露方法:

細(xì)節(jié):

部件:

細(xì)節(jié):

包: "golang.org/x/sync/singleflight"

作用:防擊穿。瞬時(shí)的相同請(qǐng)求只調(diào)用一次,response 被所有相同請(qǐng)求共享。

設(shè)計(jì)思路:按請(qǐng)求的 key 分組(一個(gè) *call 是一個(gè)組,用 map 映射存儲(chǔ)組),每個(gè)組只進(jìn)行一次訪(fǎng)問(wèn),組內(nèi)每個(gè)協(xié)程會(huì)獲得對(duì)應(yīng)結(jié)果的一個(gè)拷貝。

結(jié)構(gòu):

邏輯:

細(xì)節(jié):

部件:

如有錯(cuò)誤,請(qǐng)批評(píng)指正。

新聞名稱(chēng):go語(yǔ)言可視化設(shè)計(jì) Go設(shè)計(jì)模式
轉(zhuǎn)載來(lái)于:http://aaarwkj.com/article32/docpesc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、品牌網(wǎng)站建設(shè)外貿(mào)建站、App開(kāi)發(fā)、網(wǎng)站設(shè)計(jì)微信公眾號(hào)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
青青青久热国产精品视频| 青青草国产成人自拍视频在线观看| 国产日韩视频一区二区| 中文字幕人妻少妇美臀| 日本欧美高清一区二区| 国产福利精品一区二区av| 国产精品亚洲二区三区| 熟女另类视频在线观看| 亚洲欧美日韩激情另类| 亚洲精品色播一区二区| 免费在线免费观看av| 亚洲日本成人av在线观看| 91麻豆亚洲国产成人久久| 日本黄色免费在线观看网站 | 国产国产成年年人免费看片| 国产成人国产三级国产精品| 国精品午夜福利视频不卡| 国产成人av中文字暮在线| 日本韩国三级伦理在线观看| 国产69精品久久久久久人| 日本理论高清在线观看| 色香蕉精品国产综合| 美女高潮啪啪啪91| 欧美日韩精品视频网站| 大胆丰满邻居少妇在线观看| 国产成人免费视频大全| 国产成人精品视频午夜蜜蜂| 日本性电影一区二区| 快播av手机在线播放| 精品欧美一区二区精品| 麻豆映画传媒在线播放| 亚洲国产精品区一区二区| 欧美日韩国产一区二区三区在线观看 | 久久国产高清亚洲电影| 开心五月六月婷婷在线 | 在线观看后入大屁股| 久久精品91久久久| 中文字幕乱码亚洲2019| 一级丰满少妇av大片| 91亚洲精品一区二区三区| 国产精品一区二区综合亚洲|