最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go中過濾范型集合性能示例詳解

 更新時間:2023年03月08日 08:49:07   作者:洛天楓  
這篇文章主要為大家介紹了Go中過濾范型集合性能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

最近,我有機會在一個真實的 Golang 場景中使用泛型,同時尋找與 Stream filter(Predicate<? super T> predicate)和 Python list comprehension 等同的函數。我沒有依賴現有的包,而是選擇自己寫一個過濾函數,以達到學習的目的。

func filterStrings(collection []string, test func(string) bool) (f []string) {
 for _, s := range collection {
  if test(s) {
   f = append(f, s)
  }
 }
 return
}

然而,這只適用于字符串。如果我需要過濾一個整數的集合,那么我就需要另一個極其相似的函數。

這對于一個范型函數來說似乎是一個完美的選擇。

func filter[T any](collection []T, test func(T) bool) (f []T) {
	for _, e := range collection {
		if test(e) {
			f = append(f, e)
		}
	}
	return
}

分析類型化和范型版本之間的(少數)差異

  • 函數名后面是一個范型T的定義。
  • T被定義為任何類型。
  • 輸入 slice 中元素的類型從字符串變成了T
  • 輸入、輸出的 clice 類型也從字符串變成了T

不多說了,讓我們來寫一些單元測試。首先,我需要一個隨機集合(在我的例子中,是字符串)的生成器。

func generateStringCollection(size, strLen int) []string {
	var collection []string
	for i := 0; i &lt; size; i++ {
		collection = append(collection, strings.Repeat(fmt.Sprintf("%c", rune('A'+(i%10))), strLen))
	}
	return collection
}

現在我可以寫一個測試用例,判斷 filterStrings 函數的輸出與我的過濾范型器的輸出相同。

func TestFilter(t *testing.T) {
	c := generateStringCollection(1000, 3)
	t.Run("the output of the typed and generic functions is the same", func(t *testing.T) {
		predicate := func(s string) bool { return s == "AAA" }
		filteredStrings := filterStrings(c, predicate)
		filteredElements := filter(c, predicate)
		if !reflect.DeepEqual(filteredStrings, filteredElements) {
			t.Errorf("the output of the two functions is not the same")
		}
	})
}
=== RUN   TestFilter
=== RUN   TestFilter/the_output_of_the_typed_and_generic_functions_is_the_same
--- PASS: TestFilter (0.00s)
    --- PASS: TestFilter/the_output_of_the_typed_and_generic_functions_is_the_same (0.00s)
PASS

考慮新函數在處理大的 slice 時的性能問題。我怎樣才能確保它在這種情況下也能表現良好?

答案是:基準測試。用Go編寫基準測試與單元測試很相似。

const (
	CollectionSize = 1000
	ElementSize    = 3
)
func BenchmarkFilter_Typed_Copying(b *testing.B) {
	c := generateStringCollection(CollectionSize, ElementSize)
	b.Run("Equals to AAA", func(b *testing.B) {
		for i := 0; i &lt; b.N; i++ {
			filterStrings(c, func(s string) bool { return s == "AAA" })
		}
	})
}
func BenchmarkFilter_Generics_Copying(b *testing.B) {
	c := generateStringCollection(CollectionSize, ElementSize)
	b.Run("Equals to AAA", func(b *testing.B) {
		for i := 0; i &lt; b.N; i++ {
			filter(c, func(s string) bool { return s == "AAA" })
		}
	})
}
go test -bench=. -count=10 -benchmem
goos: darwin
goarch: arm64
pkg: github.com/timliudream/go-test/generic_test
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             718408              1641 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             718148              1640 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             732939              1655 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             723036              1639 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             699075              1639 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             707232              1643 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             616422              1652 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             730702              1649 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             691488              1700 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             717043              1646 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          428851              2754 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          428437              2762 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          430444              2800 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          429314              2757 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          430938              2754 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          429795              2754 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          426714              2755 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          418152              2755 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          431739              2761 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          412221              2755 ns/op            4080 B/op          8 allocs/op
PASS
ok      github.com/timliudream/go-test/generic_test     25.005s

我對這個結果并不滿意??雌饋砦矣每勺x性換取了性能。

此外,我對分配的數量也有點擔心。你注意到我的測試名稱中的_Copying后綴了嗎?那是因為我的兩個過濾函數都是將過濾后的項目從輸入集合復制到輸出集合中。為什么我必須為這樣一個簡單的任務占用內存?

到最后,我需要做的是過濾原始的收集。我決定先解決這個問題。

func filterInPlace[T any](collection []T, test func(T) bool) []T {
	var position, size = 0, len(collection)
	for i := 0; i &lt; size; i++ {
		if test(collection[i]) {
			collection[position] = collection[i]
			position++
		}
	}
	return collection[:position]
}

我不是把過濾后的結果寫到一個新的集合中,然后再返回,而是把結果寫回原來的集合中,并保留一個額外的索引,以便在過濾后的項目數上 "切 "出一個片斷。

我的單元測試仍然通過,在改變了下面這行之后。

filteredStrings := filterStrings(c, predicate)
//filteredElements := filter(c, predicate)
filteredElements := filterInPlace(c, predicate) // new memory-savvy function

再添加一個 bench 方法

func BenchmarkFilter_Generics_InPlace(b *testing.B) {
 c := generateStringCollection(CollectionSize, 3)
 b.Run("Equals to AAA", func(b *testing.B) {
  for i := 0; i &lt; b.N; i++ {
   filterInPlace(c, func(s string) bool { return s == "AAA" })
  }
 })
}

結果是出色的。

go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: github.com/timliudream/go-test/generic_test
BenchmarkFilter_Typed_Copying/Equals_to_AAA-8             713928              1642 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Copying/Equals_to_AAA-8          426055              2787 ns/op            4080 B/op          8 allocs/op
BenchmarkFilter_Generics_Inplace/Equals_to_AAA-8          483994              2467 ns/op               0 B/op          0 allocs/op
PASS
ok      github.com/timliudream/go-test/generic_test     4.925s

不僅內存分配歸零,而且性能也明顯提高。

以上就是Go中過濾范型集合性能示例詳解的詳細內容,更多關于Go過濾范型集合性的資料請關注腳本之家其它相關文章!

相關文章

  • 淺析Go中關于零值和空值判斷的問題

    淺析Go中關于零值和空值判斷的問題

    這篇文章主要是對零值和空值判斷現狀進行簡單的梳理和分享,文中的示例代碼講解詳細,對我們深入了解go語言有一定的幫助,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-08-08
  • 深入分析Golang Server源碼實現過程

    深入分析Golang Server源碼實現過程

    這篇文章深入介紹了Golang Server源碼實現過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-02-02
  • Go實現文件上傳和下載

    Go實現文件上傳和下載

    這篇文章主要為大家詳細介紹了Go實現文件上傳和下載,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Go通過goroutine實現多協(xié)程文件上傳的基本流程

    Go通過goroutine實現多協(xié)程文件上傳的基本流程

    多協(xié)程文件上傳是指利用多線程或多協(xié)程技術,同時上傳一個或多個文件,以提高上傳效率和速度,本文給大家介紹了Go通過goroutine實現多協(xié)程文件上傳的基本流程,需要的朋友可以參考下
    2024-05-05
  • 深入解析golang編程中函數的用法

    深入解析golang編程中函數的用法

    這篇文章主要介紹了golang編程中函數的用法,是Go語言入門學習中的基礎知識,需要的朋友可以參考下
    2015-10-10
  • golang中的單引號轉義問題

    golang中的單引號轉義問題

    這篇文章主要介紹了golang中的單引號轉義問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • go語言實現通過FTP庫自動上傳web日志

    go語言實現通過FTP庫自動上傳web日志

    這篇文章主要介紹了go語言實現通過FTP庫自動上傳web日志,非常簡單實用,需要的小伙伴快來參考下吧。
    2015-03-03
  • Golang實現smtp郵件發(fā)送的示例代碼

    Golang實現smtp郵件發(fā)送的示例代碼

    這篇文章主要為大家詳細介紹了Golang實現smtp郵件發(fā)送的相關知識,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • 詳解Go channel管道的運行原理

    詳解Go channel管道的運行原理

    Go推薦通過通信來共享內存,而channel就實現了這一理念。那channel是怎么運行的呢?本文將帶你搞懂Go channel管道的運行原理,感興趣的同學可以參考一下
    2023-05-05
  • Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法

    Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法

    這篇文章主要介紹了Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法,示例都是使用os包下的函數,需要的朋友可以參考下
    2015-10-10

最新評論

兰考县| 临汾市| 宜君县| 庄浪县| 镇坪县| 玛纳斯县| 天长市| 盱眙县| 开原市| 石景山区| 东阿县| 武清区| 富宁县| 石首市| 北安市| 喜德县| 宜黄县| 邛崃市| 邢台县| 宾阳县| 砀山县| 阜南县| 大余县| 新田县| 霍林郭勒市| 行唐县| 葫芦岛市| 栖霞市| 湘西| 正定县| 潜江市| 璧山县| 纳雍县| 宜宾县| 临桂县| 德化县| 马鞍山市| 辉县市| 榆社县| 孝感市| 西青区|