自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用位運(yùn)算為你的程序加速

開發(fā) 前端
優(yōu)化之前是遍歷這個(gè)集合來進(jìn)行判斷的,這樣的時(shí)間復(fù)雜度為 O(N),但當(dāng)我們換成位運(yùn)算就不一樣了,時(shí)間復(fù)雜度直接就變?yōu)镺(1)了,同時(shí)還節(jié)省了一個(gè)切片的存儲(chǔ)空間。

前言

最近在持續(xù)優(yōu)化之前編寫的 JSON 解析庫(kù) xjson,主要是兩個(gè)方面的優(yōu)化。

第一個(gè)是支持將一個(gè) JSONObject 對(duì)象輸出為 JSON 字符串。

這點(diǎn)在上個(gè)版本中只是利用自帶的 Print 函數(shù)打印數(shù)據(jù):

func TestJson4(t *testing.T)  {
str := `{"people":{"name":{"first":"bob"}}}`
first := xjson.Get(str, "people.name.first")
assert.Equal(t, first.String(), "bob")
get := xjson.Get(str, "people")
fmt.Println(get.String())
//assert.Equal(t, get.String(),`{"name":{"first":"bob"}}`)
}

Output:

map[name:map[first:bob]]

本次優(yōu)化之后便能直接輸出 JSON 字符串了:

圖片

實(shí)現(xiàn)過程也很簡(jiǎn)單,只需要遞歸遍歷 object 中的數(shù)據(jù),然后拼接字符串即可,核心代碼如下:

func (r Result) String() string {
switch r.Token {
case String:
return fmt.Sprint(r.object)
case Bool:
return fmt.Sprint(r.object)
case Number:
i, _ := strconv.Atoi(fmt.Sprint(r.object))
return fmt.Sprintf("%d", i)
case Float:
i, _ := strconv.ParseFloat(fmt.Sprint(r.object), 64)
return fmt.Sprintf("%f", i)
case JSONObject:
return object2JSONString(r.object)
case ArrayObject:
return object2JSONString(r.Array())
default:
return ""
}
}

圖片

用位運(yùn)算優(yōu)化

第二個(gè)優(yōu)化主要是提高了性能,查詢一個(gè)復(fù)雜 JSON 數(shù)據(jù)的時(shí)候性能提高了大約 ?16%.

# 優(yōu)化前
BenchmarkDecode-12 90013 66905 ns/op 42512 B/op 1446 allocs/op
# 優(yōu)化后
BenchmarkDecode-12 104746 59766 ns/op 37749 B/op 1141 allocs/op

這里截取了一些重點(diǎn)改動(dòng)的部分:

圖片

在 JSON 解析過程中會(huì)有一個(gè)有限狀態(tài)機(jī)狀態(tài)遷移的過程,而遷移的時(shí)候可能會(huì)出現(xiàn)多個(gè)狀態(tài)。

比如當(dāng)前解析到的 token 值為 {,那它接下來的 token 可能會(huì)為 ObjectKey:"name",也可能會(huì)是 BeginObject:{,當(dāng)然也可能會(huì)是 EndObject:}, 所以在優(yōu)化之前我是將狀態(tài)全部存放在一個(gè)集合中的,在解析過程中如果發(fā)現(xiàn)狀態(tài)不滿足預(yù)期的列表時(shí)則會(huì)拋出語(yǔ)法異常的錯(cuò)誤。

圖片

所以優(yōu)化之前是遍歷這個(gè)集合來進(jìn)行判斷的,這樣的時(shí)間復(fù)雜度為 O(N),但當(dāng)我們換成位運(yùn)算就不一樣了,時(shí)間復(fù)雜度直接就變?yōu)镺(1)了,同時(shí)還節(jié)省了一個(gè)切片的存儲(chǔ)空間。

我們簡(jiǎn)單來分析下這個(gè)位運(yùn)算為什么會(huì)達(dá)到判斷一個(gè)數(shù)據(jù)是否在一個(gè)集合中同樣的效果。

首先以這兩個(gè)狀態(tài)為例:

StatusObjectKey   status = 0x0002
StatusColon status = 0x0004

他們分別對(duì)應(yīng)的二進(jìn)制數(shù)據(jù)為:

StatusObjectKey   status = 0x0002 //0010
StatusColon status = 0x0004 //0100

當(dāng)我們對(duì)這兩個(gè)數(shù)據(jù)求 | 運(yùn)算得到的數(shù)據(jù)是 0110:

A:0010
B:0100

C:0110

這時(shí)候如何我們?nèi)绻眠@兩個(gè)原始數(shù)據(jù)與 C:0110 做 & 運(yùn)算時(shí)就會(huì)還原為剛才的兩個(gè)數(shù)據(jù)。

// input:
A:0010
C:0110

// output:
A:0010

----------
// input:
B:0100
C:0110

// output:
B:0100

但我們換一個(gè) D 與 C 求 & 時(shí):

D: 1000 // 0x0008 對(duì)應(yīng)的二進(jìn)制為 1000
C: 0110
D':0000

將會(huì)得到一個(gè) 0 值,只要得出的數(shù)據(jù)大于 0 我們就能判斷一個(gè)數(shù)據(jù)是否在給定的集合中了。

當(dāng)然這里有一個(gè)前提條件就是,我們輸入的數(shù)據(jù)高位永遠(yuǎn)都是是 1 才行,也就是2的冪。

同樣的優(yōu)化在解析查詢語(yǔ)法時(shí)也有使用:

圖片

其他奇淫巧技

當(dāng)然位運(yùn)算還有一些其他技巧,比如判斷奇偶數(shù):

// 偶數(shù)
a & 1 == 0

// 奇數(shù)
a & 1 == 1

乘法和除法,右移1一位是除以2,左移一位是乘以2.

x := 2
fmt.Println(x>>1) //1
fmt.Println(x<<1) //4

總結(jié)

位運(yùn)算在帶來程序性能提升的同時(shí)也降低代碼可讀性,所以我們得按需選擇是否使用;

再一些底層庫(kù)、框架代碼對(duì)性能有極致追求的場(chǎng)景推薦使用,但在業(yè)務(wù)代碼中對(duì)數(shù)據(jù)做加減乘除就沒必要用位運(yùn)算了,只會(huì)讓后續(xù)的維護(hù)者一臉懵逼。

相關(guān)代碼:https://github.com/crossoverJie/xjson

責(zé)任編輯:武曉燕 來源: crossoverJie
相關(guān)推薦

2020-03-25 10:44:16

位運(yùn)算操作技巧

2022-05-18 16:06:15

位運(yùn)算異或運(yùn)算

2022-05-23 15:02:19

異或運(yùn)算面試真題

2020-06-18 09:04:59

CC++程序

2023-09-19 23:17:43

Python緩存

2021-02-21 06:36:57

運(yùn)算技巧按位

2012-05-05 08:52:14

iPhone

2014-04-21 16:24:33

Web啟動(dòng)畫面

2013-03-25 09:41:20

PythonCython

2013-11-05 13:19:37

設(shè)計(jì)加速

2021-10-11 09:41:20

React位運(yùn)算技巧前端

2021-09-23 14:44:24

程序員計(jì)算機(jī)開發(fā)

2019-08-21 13:40:50

2021-10-11 19:01:47

CPU位運(yùn)算JS

2009-07-31 16:48:44

C#位運(yùn)算

2011-05-03 09:14:45

QtOvi商店Symbian

2011-07-15 17:05:14

2016-01-14 09:45:46

健在牛叉程序員

2011-01-13 14:38:00

JavascriptCSSWeb

2020-07-23 14:15:42

Cython的Python代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)