測試使用bytes.buffer()的單線程與多線程的寫效率

1. 測試代碼

func main() {
	type Buffer struct {
		sb bytes.Buffer
		// 線程鎖
		rw sync.RWMutex
		// 等待線程運行完畢
		wg sync.WaitGroup
	}
	var buffer Buffer
	now := time.Now()
	for i := 0; i < 1000000; i++ {
		// 官方推薦用法
		buffer.wg.Add(1)
		go func() {
			// 加鎖
			buffer.rw.Lock()
			// 運行完解鎖
			defer buffer.rw.Unlock()
			buffer.sb.WriteString("壬戌之秋,七月既望,蘇子與客泛舟遊於赤壁之下。清風徐來,水波不興。舉酒屬客,誦明月之詩,歌窈窕之章。少焉,月出於東山之上,徘徊於斗牛之間。白露橫江,水光接天。縱一葦之所如,凌萬頃之茫然。浩浩乎如馮虛御風,而不知其所止;飄飄乎如遺世獨立,羽化而登仙。")
			buffer.sb.WriteString("於是飲酒樂甚,扣舷而歌之。歌曰:“桂棹兮蘭槳,擊空明兮溯流光。渺渺兮予懷,望美人兮天一方。”客有吹洞簫者,倚歌而和之。其聲嗚嗚然,如怨如慕,如泣如訴,餘音嫋嫋,不絕如縷。舞幽壑之潛蛟,泣孤舟之嫠婦。")
			buffer.sb.WriteString("蘇子愀然,正襟危坐而問客曰:“何爲其然也?”客曰:“月明星稀,烏鵲南飛,此非曹孟德之詩乎?西望夏口,東望武昌,山川相繆,鬱乎蒼蒼,此非孟德之困於周郎者乎?方其破荊州,下江陵,順流而東也,舳艫千里,旌旗蔽空,釃酒臨江,橫槊賦詩,固一世之雄也,而今安在哉?況吾與子漁樵於江渚之上,侶魚蝦而友麋鹿,駕一葉之扁舟,舉匏樽以相屬。寄蜉蝣於天地,渺滄海之一粟。哀吾生之須臾,羨長江之無窮。挾飛仙以遨遊,抱明月而長終。知不可乎驟得,託遺響於悲風。”")
			buffer.sb.WriteString("蘇子曰:“客亦知夫水與月乎?逝者如斯,而未嘗往也;盈虛者如彼,而卒莫消長也。蓋將自其變者而觀之,則天地曾不能以一瞬;自其不變者而觀之,則物與我皆無盡也,而又何羨乎!且夫天地之間,物各有主,苟非吾之所有,雖一毫而莫取。惟江上之清風,與山間之明月,耳得之而爲聲,目遇之而成色,取之無禁,用之不竭,是造物者之無盡藏也,而吾與子之所共適。”")
			buffer.sb.WriteString("客喜而笑,洗盞更酌。餚核既盡,杯盤狼籍。相與枕藉乎舟中,不知東方之既白。")
			defer buffer.wg.Add(-1)
		}()
	}
	after := time.Since(now)
	fmt.Printf("running time %s\n", after)
}

// 運行時間0.836s(運行十次取平均數)


func main() {
	type Buffer struct {
		sb bytes.Buffer
		rw sync.RWMutex
		wg sync.WaitGroup
	}
	var buffer Buffer
	now := time.Now()
	for i := 0; i < 1000000; i++ {
		buffer.sb.WriteString("壬戌之秋,七月既望,蘇子與客泛舟遊於赤壁之下。清風徐來,水波不興。舉酒屬客,誦明月之詩,歌窈窕之章。少焉,月出於東山之上,徘徊於斗牛之間。白露橫江,水光接天。縱一葦之所如,凌萬頃之茫然。浩浩乎如馮虛御風,而不知其所止;飄飄乎如遺世獨立,羽化而登仙。")
		buffer.sb.WriteString("於是飲酒樂甚,扣舷而歌之。歌曰:“桂棹兮蘭槳,擊空明兮溯流光。渺渺兮予懷,望美人兮天一方。”客有吹洞簫者,倚歌而和之。其聲嗚嗚然,如怨如慕,如泣如訴,餘音嫋嫋,不絕如縷。舞幽壑之潛蛟,泣孤舟之嫠婦。")
		buffer.sb.WriteString("蘇子愀然,正襟危坐而問客曰:“何爲其然也?”客曰:“月明星稀,烏鵲南飛,此非曹孟德之詩乎?西望夏口,東望武昌,山川相繆,鬱乎蒼蒼,此非孟德之困於周郎者乎?方其破荊州,下江陵,順流而東也,舳艫千里,旌旗蔽空,釃酒臨江,橫槊賦詩,固一世之雄也,而今安在哉?況吾與子漁樵於江渚之上,侶魚蝦而友麋鹿,駕一葉之扁舟,舉匏樽以相屬。寄蜉蝣於天地,渺滄海之一粟。哀吾生之須臾,羨長江之無窮。挾飛仙以遨遊,抱明月而長終。知不可乎驟得,託遺響於悲風。”")
		buffer.sb.WriteString("蘇子曰:“客亦知夫水與月乎?逝者如斯,而未嘗往也;盈虛者如彼,而卒莫消長也。蓋將自其變者而觀之,則天地曾不能以一瞬;自其不變者而觀之,則物與我皆無盡也,而又何羨乎!且夫天地之間,物各有主,苟非吾之所有,雖一毫而莫取。惟江上之清風,與山間之明月,耳得之而爲聲,目遇之而成色,取之無禁,用之不竭,是造物者之無盡藏也,而吾與子之所共適。”")
		buffer.sb.WriteString("客喜而笑,洗盞更酌。餚核既盡,杯盤狼籍。相與枕藉乎舟中,不知東方之既白。")
	}
	after := time.Since(now)
	fmt.Printf("running time %s\n", after)
}
// 運行時間2.06s(運行十次取平均數)

2. 結論

  1. 單次遍歷要寫入的數據量很大時,多線程的運行效率會遠遠超出單線程的運行效率,如果遍歷次數很多,推薦使用多線程,如果次數較少,就看需求決定了
  2. 要寫入的數據量很小時,多線程的運行效率會遠遠低於單線程的運行效率,不論是單次遍歷還是多次遍歷,都推薦使用單線程,這是因爲線程的創建銷燬鎖的控制也是需要時間的,此時逐次寫入少量數據的時間要小於線程創建和銷燬的時間

3. 知識點

  1. WaitGroup類型
    WaitGroup用於等待一組線程的結束。父線程調用Add方法來設定應等待的線程的數量。每個被等待的線程在結束時應調用Done方法。同時,主線程裏可以調用Wait方法阻塞至所有線程結束。
  2. Add方法
    Add方法向內部計數加上delta,delta可以是負數;如果內部計數器變爲0,Wait方法阻塞等待的所有線程都會釋放,如果計數器小於0,方法panic。注意Add加上正數的調用應在Wait之前,否則Wait可能只會等待很少的線程。一般來說本方法應在創建新的線程或者其他應等待的事件之前調用。
  3. Wait方法
    Wait方法阻塞直到WaitGroup計數器減爲0。
  4. 鎖的實現
sync.Mutex(互斥鎖) sync.RWMutex(讀寫鎖)
當一個goroutine訪問的時候,其他goroutine都不能訪問,保證了資源的同步,避免了競爭,不過也降低了性能 非寫狀態時:多個Goroutine可以同時讀,一個Goroutine寫的時候,其它Goroutine不能讀也不能寫,性能好
  1. bytes.buffer()不是線程安全的,如果要單次遍歷的時候寫入順序是有序的,需要加鎖
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章