国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Go語言核心36講(Go語言實(shí)戰(zhàn)與應(yīng)用十三)--學(xué)習(xí)筆記

不知名網(wǎng)友 / 2302人閱讀

摘要:在第二種方案中,我們封裝的結(jié)構(gòu)體類型的所有方法,都可以與類型的方法完全一致包括方法名稱和方法簽名。所以在設(shè)計(jì)這樣的結(jié)構(gòu)體類型的時(shí)候,只包含類型的字段就不夠了。當(dāng)參數(shù)或的實(shí)際類型不符合要求時(shí),方法會(huì)立即引發(fā)。

35 | 并發(fā)安全字典sync.Map (下)

我們在上一篇文章中談到了,由于并發(fā)安全字典提供的方法涉及的鍵和值的類型都是interface{},所以我們在調(diào)用這些方法的時(shí)候,往往還需要對鍵和值的實(shí)際類型進(jìn)行檢查。

這里大致有兩個(gè)方案。我們上一篇文章中提到了第一種方案,在編碼時(shí)就完全確定鍵和值的類型,然后利用 Go 語言的編譯器幫我們做檢查。

這樣做很方便,不是嗎?不過,雖然方便,但是卻讓這樣的字典類型缺少了一些靈活性。

如果我們還需要一個(gè)鍵類型為uint32并發(fā)安全字典的話,那就不得不再如法炮制地寫一遍代碼了。因此,在需求多樣化之后,工作量反而更大,甚至?xí)a(chǎn)生很多雷同的代碼。

知識(shí)擴(kuò)展

問題 1:怎樣保證并發(fā)安全字典中的鍵和值的類型正確性?(方案二)

那么,如果我們既想保持sync.Map類型原有的靈活性,又想約束鍵和值的類型,那么應(yīng)該怎樣做呢?這就涉及了第二個(gè)方案。

在第二種方案中,我們封裝的結(jié)構(gòu)體類型的所有方法,都可以與sync.Map類型的方法完全一致(包括方法名稱和方法簽名)。

不過,在這些方法中,我們就需要添加一些做類型檢查的代碼了。另外,這樣并發(fā)安全字典的鍵類型和值類型,必須在初始化的時(shí)候就完全確定。并且,這種情況下,我們必須先要保證鍵的類型是可比較的。

所以在設(shè)計(jì)這樣的結(jié)構(gòu)體類型的時(shí)候,只包含sync.Map類型的字段就不夠了。

比如:

type ConcurrentMap struct { m         sync.Map keyType   reflect.Type valueType reflect.Type}

這里ConcurrentMap類型代表的是:可自定義鍵類型和值類型的并發(fā)安全字典。這個(gè)類型同樣有一個(gè)sync.Map類型的字段m,代表著其內(nèi)部使用的并發(fā)安全字典。

另外,它的字段keyType和valueType,分別用于保存鍵類型和值類型。這兩個(gè)字段的類型都是reflect.Type,我們可稱之為反射類型。

這個(gè)類型可以代表 Go 語言的任何數(shù)據(jù)類型。并且,這個(gè)類型的值也非常容易獲得:通過調(diào)用reflect.TypeOf函數(shù)并把某個(gè)樣本值傳入即可。

調(diào)用表達(dá)式reflect.TypeOf(int(123))的結(jié)果值,就代表了int類型的反射類型值。

我們現(xiàn)在來看一看ConcurrentMap類型方法應(yīng)該怎么寫。

先說Load方法,這個(gè)方法接受一個(gè)interface{}類型的參數(shù)key,參數(shù)key代表了某個(gè)鍵的值。

因此,當(dāng)我們根據(jù) ConcurrentMap 在m字段的值中查找鍵值對的時(shí)候,就必須保證 ConcurrentMap 的類型是正確的。由于反射類型值之間可以直接使用操作符==或!=進(jìn)行判等,所以這里的類型檢查代碼非常簡單。

func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) { if reflect.TypeOf(key) != cMap.keyType {  return } return cMap.m.Load(key)}

我們把一個(gè)接口類型值傳入reflect.TypeOf函數(shù),就可以得到與這個(gè)值的實(shí)際類型對應(yīng)的反射類型值。

因此,如果參數(shù)值的反射類型與keyType字段代表的反射類型不相等,那么我們就忽略后續(xù)操作,并直接返回。

這時(shí),Load方法的第一個(gè)結(jié)果value的值為nil,而第二個(gè)結(jié)果ok的值為false。這完全符合Load方法原本的含義。

再來說Store方法。Store方法接受兩個(gè)參數(shù)key和value,它們的類型也都是interface{}。因此,我們的類型檢查應(yīng)該針對它們來做。

func (cMap *ConcurrentMap) Store(key, value interface{}) { if reflect.TypeOf(key) != cMap.keyType {  panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key))) } if reflect.TypeOf(value) != cMap.valueType {  panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value))) } cMap.m.Store(key, value)}

這里的類型檢查代碼與Load方法中的代碼很類似,不同的是對檢查結(jié)果的處理措施。當(dāng)參數(shù)key或value的實(shí)際類型不符合要求時(shí),Store方法會(huì)立即引發(fā) panic。

這主要是由于Store方法沒有結(jié)果聲明,所以在參數(shù)值有問題的時(shí)候,它無法通過比較平和的方式告知調(diào)用方。不過,這也是符合Store方法的原本含義的。

如果你不想這么做,也是可以的,那么就需要為Store方法添加一個(gè)error類型的結(jié)果。

并且,在發(fā)現(xiàn)參數(shù)值類型不正確的時(shí)候,讓它直接返回相應(yīng)的error類型值,而不是引發(fā) panic。要知道,這里展示的只一個(gè)參考實(shí)現(xiàn),你可以根據(jù)實(shí)際的應(yīng)用場景去做優(yōu)化和改進(jìn)。

至于與ConcurrentMap類型相關(guān)的其他方法和函數(shù),我在這里就不展示了。它們在類型檢查方式和處理流程上并沒有特別之處。你可以在 demo72.go 文件中看到這些代碼。

稍微總結(jié)一下。第一種方案適用于我們可以完全確定鍵和值具體類型的情況。在這種情況下,我們可以利用 Go 語言編譯器去做類型檢查,并用類型斷言表達(dá)式作為輔助,就像IntStrMap那樣。

在第二種方案中,我們無需在程序運(yùn)行之前就明確鍵和值的類型,只要在初始化并發(fā)安全字典的時(shí)候,動(dòng)態(tài)地給定它們就可以了。這里主要需要用到reflect包中的函數(shù)和數(shù)據(jù)類型,外加一些簡單的判等操作。

第一種方案存在一個(gè)很明顯的缺陷,那就是無法靈活地改變字典的鍵和值的類型。一旦需求出現(xiàn)多樣化,編碼的工作量就會(huì)隨之而來。

第二種方案很好地彌補(bǔ)了這一缺陷,但是,那些反射操作或多或少都會(huì)降低程序的性能。我們往往需要根據(jù)實(shí)際的應(yīng)用場景,通過嚴(yán)謹(jǐn)且一致的測試,來獲得和比較程序的各項(xiàng)指標(biāo),并以此作為方案選擇的重要依據(jù)之一。

問題 2:并發(fā)安全字典如何做到盡量避免使用鎖?

sync.Map類型在內(nèi)部使用了大量的原子操作來存取鍵和值,并使用了兩個(gè)原生的map作為存儲(chǔ)介質(zhì)。

其中一個(gè)原生map被存在了sync.Map的read字段中,該字段是sync/atomic.Value類型的。 這個(gè)原生字典可以被看作一個(gè)快照,它總會(huì)在條件滿足時(shí),去重新保存所屬的sync.Map值中包含的所有鍵值對。

為了描述方便,我們在后面簡稱它為只讀字典。不過,只讀字典雖然不會(huì)增減其中的鍵,但卻允許變更其中的鍵所對應(yīng)的值。所以,它并不是傳統(tǒng)意義上的快照,它的只讀特性只是對于其中鍵的集合而言的。

由read字段的類型可知,sync.Map在替換只讀字典的時(shí)候根本用不著鎖。另外,這個(gè)只讀字典在存儲(chǔ)鍵值對的時(shí)候,還在值之上封裝了一層。

它先把值轉(zhuǎn)換為了unsafe.Pointer類型的值,然后再把后者封裝,并儲(chǔ)存在其中的原生字典中。如此一來,在變更某個(gè)鍵所對應(yīng)的值的時(shí)候,就也可以使用原子操作了。

sync.Map中的另一個(gè)原生字典由它的dirty字段代表。 它存儲(chǔ)鍵值對的方式與read字段中的原生字典一致,它的鍵類型也是interface{},并且同樣是把值先做轉(zhuǎn)換和封裝后再進(jìn)行儲(chǔ)存的。我們暫且把它稱為臟字典。

注意,臟字典和只讀字典如果都存有同一個(gè)鍵值對,那么這里的兩個(gè)鍵指的肯定是同一個(gè)基本值,對于兩個(gè)值來說也是如此。

正如前文所述,這兩個(gè)字典在存儲(chǔ)鍵和值的時(shí)候都只會(huì)存入它們的某個(gè)指針,而不是基本值。

sync.Map在查找指定的鍵所對應(yīng)的值的時(shí)候,總會(huì)先去只讀字典中尋找,并不需要鎖定互斥鎖。只有當(dāng)確定“只讀字典中沒有,但臟字典中可能會(huì)有這個(gè)鍵”的時(shí)候,它才會(huì)在鎖的保護(hù)下去訪問臟字典。

相對應(yīng)的,sync.Map在存儲(chǔ)鍵值對的時(shí)候,只要只讀字典中已存有這個(gè)鍵,并且該鍵值對未被標(biāo)記為“已刪除”,就會(huì)把新值存到里面并直接返回,這種情況下也不需要用到鎖。

否則,它才會(huì)在鎖的保護(hù)下把鍵值對存儲(chǔ)到臟字典中。這個(gè)時(shí)候,該鍵值對的“已刪除”標(biāo)記會(huì)被抹去。

image

sync.Map 中的 read 與 dirty

順便說一句,只有當(dāng)一個(gè)鍵值對應(yīng)該被刪除,但卻仍然存在于只讀字典中的時(shí)候,才會(huì)被用標(biāo)記為“已刪除”的方式進(jìn)行邏輯刪除,而不會(huì)直接被物理刪除。

這種情況會(huì)在重建臟字典以后的一段時(shí)間內(nèi)出現(xiàn)。不過,過不了多久,它們就會(huì)被真正刪除掉。在查找和遍歷鍵值對的時(shí)候,已被邏輯刪除的鍵值對永遠(yuǎn)會(huì)被無視。

對于刪除鍵值對,sync.Map會(huì)先去檢查只讀字典中是否有對應(yīng)的鍵。如果沒有,臟字典中可能有,那么它就會(huì)在鎖的保護(hù)下,試圖從臟字典中刪掉該鍵值對。

最后,sync.Map會(huì)把該鍵值對中指向值的那個(gè)指針置為nil,這是另一種邏輯刪除的方式。

除此之外,還有一個(gè)細(xì)節(jié)需要注意,只讀字典和臟字典之間是會(huì)互相轉(zhuǎn)換的。在臟字典中查找鍵值對次數(shù)足夠多的時(shí)候,sync.Map會(huì)把臟字典直接作為只讀字典,保存在它的read字段中,然后把代表臟字典的dirty字段的值置為nil。

在這之后,一旦再有新的鍵值對存入,它就會(huì)依據(jù)只讀字典去重建臟字典。這個(gè)時(shí)候,它會(huì)把只讀字典中已被邏輯刪除的鍵值對過濾掉。理所當(dāng)然,這些轉(zhuǎn)換操作肯定都需要在鎖的保護(hù)下進(jìn)行。

image

sync.Map 中 read 與 dirty 的互換

綜上所述,sync.Map的只讀字典和臟字典中的鍵值對集合,并不是實(shí)時(shí)同步的,它們在某些時(shí)間段內(nèi)可能會(huì)有不同。

由于只讀字典中鍵的集合不能被改變,所以其中的鍵值對有時(shí)候可能是不全的。相反,臟字典中的鍵值對集合總是完全的,并且其中不會(huì)包含已被邏輯刪除的鍵值對。

因此,可以看出,在讀操作有很多但寫操作卻很少的情況下,并發(fā)安全字典的性能往往會(huì)更好。在幾個(gè)寫操作當(dāng)中,新增鍵值對的操作對并發(fā)安全字典的性能影響是最大的,其次是刪除操作,最后才是修改操作。

如果被操作的鍵值對已經(jīng)存在于sync.Map的只讀字典中,并且沒有被邏輯刪除,那么修改它并不會(huì)使用到鎖,對其性能的影響就會(huì)很小。

總結(jié)

這兩篇文章中,我們討論了sync.Map類型,并談到了怎樣保證并發(fā)安全字典中的鍵和值的類型正確性。

為了進(jìn)一步明確并發(fā)安全字典中鍵值的實(shí)際類型,這里大致有兩種方案可選。

  • 其中一種方案是,在編碼時(shí)就完全確定鍵和值的類型,然后利用 Go 語言的編譯器幫我們做檢查。
  • 另一種方案是,接受動(dòng)態(tài)的類型設(shè)置,并在程序運(yùn)行的時(shí)候通過反射操作進(jìn)行檢查。

這兩種方案各有利弊,前一種方案在擴(kuò)展性方面有所欠缺,而后一種方案通常會(huì)影響到程序的性能。在實(shí)際使用的時(shí)候,我們一般都需要通過客觀的測試來幫助決策。

另外,在有些時(shí)候,與單純使用原生字典和互斥鎖的方案相比,使用sync.Map可以顯著地減少鎖的爭用。sync.Map本身確實(shí)也用到了鎖,但是,它會(huì)盡可能地避免使用鎖。

可能地避免使用鎖。這就要說到sync.Map對其持有兩個(gè)原生字典的巧妙使用了。這兩個(gè)原生字典一個(gè)被稱為只讀字典,另一個(gè)被稱為臟字典。通過對它們的分析,我們知道了并發(fā)安全字典的適用場景,以及每種操作對其性能的影響程度。

思考題

今天的思考題是:關(guān)于保證并發(fā)安全字典中的鍵和值的類型正確性,你還能想到其他的方案嗎?

package mainimport (	"errors"	"fmt"	"reflect"	"sync")// IntStrMap 代表鍵類型為int、值類型為string的并發(fā)安全字典。type IntStrMap struct {	m sync.Map}func (iMap *IntStrMap) Delete(key int) {	iMap.m.Delete(key)}func (iMap *IntStrMap) Load(key int) (value string, ok bool) {	v, ok := iMap.m.Load(key)	if v != nil {		value = v.(string)	}	return}func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {	a, loaded := iMap.m.LoadOrStore(key, value)	actual = a.(string)	return}func (iMap *IntStrMap) Range(f func(key int, value string) bool) {	f1 := func(key, value interface{}) bool {		return f(key.(int), value.(string))	}	iMap.m.Range(f1)}func (iMap *IntStrMap) Store(key int, value string) {	iMap.m.Store(key, value)}// ConcurrentMap 代表可自定義鍵類型和值類型的并發(fā)安全字典。type ConcurrentMap struct {	m         sync.Map	keyType   reflect.Type	valueType reflect.Type}func NewConcurrentMap(keyType, valueType reflect.Type) (*ConcurrentMap, error) {	if keyType == nil {		return nil, errors.New("nil key type")	}	if !keyType.Comparable() {		return nil, fmt.Errorf("incomparable key type: %s", keyType)	}	if valueType == nil {		return nil, errors.New("nil value type")	}	cMap := &ConcurrentMap{		keyType:   keyType,		valueType: valueType,	}	return cMap, nil}func (cMap *ConcurrentMap) Delete(key interface{}) {	if reflect.TypeOf(key) != cMap.keyType {		return	}	cMap.m.Delete(key)}func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) {	if reflect.TypeOf(key) != cMap.keyType {		return	}	return cMap.m.Load(key)}func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {	if reflect.TypeOf(key) != cMap.keyType {		panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key)))	}	if reflect.TypeOf(value) != cMap.valueType {		panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value)))	}	actual, loaded = cMap.m.LoadOrStore(key, value)	return}func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) {	cMap.m.Range(f)}func (cMap *ConcurrentMap) Store(key, value interface{}) {	if reflect.TypeOf(key) != cMap.keyType {		panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key)))	}	if reflect.TypeOf(value) != cMap.valueType {		panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value)))	}	cMap.m.Store(key, value)}// pairs 代表測試用的鍵值對列表。var pairs = []struct {	k int	v string}{	{k: 1, v: "a"},	{k: 2, v: "b"},	{k: 3, v: "c"},	{k: 4, v: "d"},}func main() {	// 示例1。	var sMap sync.Map	//sMap.Store([]int{1, 2, 3}, 4) // 這行代碼會(huì)引發(fā)panic。	_ = sMap	// 示例2。	{		var iMap IntStrMap		iMap.Store(pairs[0].k, pairs[0].v)		iMap.Store(pairs[1].k, pairs[1].v)		iMap.Store(pairs[2].k, pairs[2].v)		fmt.Println("[Three pairs have been stored in the IntStrMap instance]")		iMap.Range(func(key int, value string) bool {			fmt.Printf("The result of an iteration in Range: %d, %s/n",				key, value)			return true		})		k0 := pairs[0].k		v0, ok := iMap.Load(k0)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v0, ok, k0)		k3 := pairs[3].k		v3, ok := iMap.Load(k3)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v3, ok, k3)		k2, v2 := pairs[2].k, pairs[2].v		actual2, loaded2 := iMap.LoadOrStore(k2, v2)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual2, loaded2, k2, v2)		v3 = pairs[3].v		actual3, loaded3 := iMap.LoadOrStore(k3, v3)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual3, loaded3, k3, v3)		k1 := pairs[1].k		iMap.Delete(k1)		fmt.Printf("[The pair with the key of %v has been removed from the IntStrMap instance]/n",			k1)		v1, ok := iMap.Load(k1)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v1, ok, k1)		v1 = pairs[1].v		actual1, loaded1 := iMap.LoadOrStore(k1, v1)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual1, loaded1, k1, v1)		iMap.Range(func(key int, value string) bool {			fmt.Printf("The result of an iteration in Range: %d, %s/n",				key, value)			return true		})	}	fmt.Println()	// 示例2。	{		cMap, err := NewConcurrentMap(			reflect.TypeOf(pairs[0].k), reflect.TypeOf(pairs[0].v))		if err != nil {			fmt.Printf("fatal error: %s", err)			return		}		cMap.Store(pairs[0].k, pairs[0].v)		cMap.Store(pairs[1].k, pairs[1].v)		cMap.Store(pairs[2].k, pairs[2].v)		fmt.Println("[Three pairs have been stored in the ConcurrentMap instance]")		cMap.Range(func(key, value interface{}) bool {			fmt.Printf("The result of an iteration in Range: %d, %s/n",				key, value)			return true		})		k0 := pairs[0].k		v0, ok := cMap.Load(k0)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v0, ok, k0)		k3 := pairs[3].k		v3, ok := cMap.Load(k3)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v3, ok, k3)		k2, v2 := pairs[2].k, pairs[2].v		actual2, loaded2 := cMap.LoadOrStore(k2, v2)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual2, loaded2, k2, v2)		v3 = pairs[3].v		actual3, loaded3 := cMap.LoadOrStore(k3, v3)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual3, loaded3, k3, v3)		k1 := pairs[1].k		cMap.Delete(k1)		fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance]/n",			k1)		v1, ok := cMap.Load(k1)		fmt.Printf("The result of Load: %v, %v (key: %v)/n",			v1, ok, k1)		v1 = pairs[1].v		actual1, loaded1 := cMap.LoadOrStore(k1, v1)		fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)/n",			actual1, loaded1, k1, v1)		cMap.Range(func(key, value interface{}) bool {			fmt.Printf("The result of an iteration in Range: %d, %s/n",				key, value)			return true		})	}}

筆記源碼

https://github.com/MingsonZheng/go-core-demo

知識(shí)共享許可協(xié)議

本作品采用知識(shí)共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議進(jìn)行許可。

歡迎轉(zhuǎn)載、使用、重新發(fā)布,但務(wù)必保留文章署名 鄭子銘 (包含鏈接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/125368.html

相關(guān)文章

  • Go語言核心36Go語言實(shí)戰(zhàn)應(yīng)用八)--學(xué)習(xí)筆記

    摘要:用于展示一種簡易的且更加寬松的互斥鎖的模擬。由于這里的原子操作函數(shù)只支持非常有限的數(shù)據(jù)類型,所以在很多應(yīng)用場景下,互斥鎖往往是更加適合的。這主要是因?yàn)樵硬僮骱瘮?shù)的執(zhí)行速度要比互斥鎖快得多。30 | 原子操作(下) 我們接著上一篇文章的內(nèi)容繼續(xù)聊,上一篇我們提到了,sync/atomic包中的函數(shù)可以做的原子操作有:加法(add)、比較并交換(compare and swap,簡稱 C...

    niuxiaowei111 評論0 收藏0
  • Go語言核心36Go語言實(shí)戰(zhàn)應(yīng)用十二)--學(xué)習(xí)筆記

    摘要:除此之外,把并發(fā)安全字典封裝在一個(gè)結(jié)構(gòu)體類型中,往往是一個(gè)很好的選擇。請看下面的代碼如上所示,我編寫了一個(gè)名為的結(jié)構(gòu)體類型,它代表了鍵類型為值類型為的并發(fā)安全字典。在這個(gè)結(jié)構(gòu)體類型中,只有一個(gè)類型的字段。34 | 并發(fā)安全字典sync.Map (上)我們今天再來講一個(gè)并發(fā)安全的高級(jí)數(shù)據(jù)結(jié)構(gòu):sync.Map。眾所周知,Go 語言自帶的字典類型map并不是并發(fā)安全的。前導(dǎo)知識(shí):并發(fā)安全字典誕生...

    不知名網(wǎng)友 評論0 收藏0
  • AI開發(fā)書籍分享

    摘要:編程書籍的整理和收集最近一直在學(xué)習(xí)深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后也找了很多的書和文章,隨著不斷的學(xué)習(xí),也整理了下自己的學(xué)習(xí)筆記準(zhǔn)備分享出來給大家后續(xù)的文章和總結(jié)會(huì)繼續(xù)分享,先分享一部分的 編程書籍的整理和收集 最近一直在學(xué)習(xí)deep learning深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后...

    huayeluoliuhen 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<