久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

Go 多級(jí)排序?qū)崙?zhàn):sort.Interface、穩(wěn)定排序與泛型封裝

Go 多級(jí)排序?qū)崙?zhàn):sort.Interface、穩(wěn)定排序與泛型封裝 1. 從一次業(yè)務(wù)需求說(shuō)起為什么 Go 的排序這么“麻煩”先說(shuō)我最近遇到的一件事。后臺(tái)管理系統(tǒng)要導(dǎo)出一張訂單列表排序規(guī)則大概是這樣的先按訂單狀態(tài)分組狀態(tài)相同就按金額降序金額也一樣就按創(chuàng)建時(shí)間升序最后再用訂單號(hào)兜底保證分頁(yè)穩(wěn)定不亂跳。你寫代碼的時(shí)候大概也發(fā)現(xiàn)了Go 的sort包跟很多語(yǔ)言的排序不太一樣。Java 里有Comparator鏈?zhǔn)秸{(diào)用Python 有key參數(shù)能傳sorted甚至 JavaScript 的array.sort((a,b)a.foo - b.foo || a.bar - b.bar)一行就搞定了。但 Go 里最簡(jiǎn)單的方式是實(shí)現(xiàn)sort.Interface把Len、Less、Swap三個(gè)方法寫出來(lái)。很多新手第一次接觸會(huì)覺(jué)得很別扭明明那么簡(jiǎn)單的排序需求怎么要寫這么多代碼。但我想說(shuō)的是這個(gè)“麻煩”恰恰是 Go 設(shè)計(jì)上的亮點(diǎn)。sort.Interface讓你把排序的規(guī)則和數(shù)據(jù)結(jié)構(gòu)徹底解耦排序算法在sort包里是通用的你只需要告訴它“什么叫做一個(gè)元素在另一個(gè)元素之前”。一旦想通了這個(gè)模型復(fù)雜排序不但不難寫反而比那種鏈?zhǔn)?Comparator 更容易排查問(wèn)題、更容易擴(kuò)展規(guī)則、也更容易寫測(cè)試。這篇文章我要聊的就是這件事用sort.Interface實(shí)現(xiàn)復(fù)雜多級(jí)排序的完整套路。包括基礎(chǔ)姿勢(shì)、多種多級(jí)排序的實(shí)現(xiàn)思路、穩(wěn)定排序的重要性、性能問(wèn)題以及一些我在實(shí)際項(xiàng)目中踩過(guò)的坑。先說(shuō)結(jié)論多級(jí)排序的核心就一句話——在Less方法里按優(yōu)先級(jí)逐級(jí)比較每一級(jí)要么返回結(jié)果要么繼續(xù)比下一級(jí)。2. 先把基礎(chǔ)打牢sort.Interface 是什么以及它為什么這么設(shè)計(jì)2.1 三個(gè)方法背后是“三件事”sort.Interface長(zhǎng)這樣type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) }它只規(guī)定了三件事集合有多大、兩個(gè)元素誰(shuí)更“小”、以及怎么交換兩個(gè)元素的位置。至于用的是什么排序算法——那是sort.Sort的事情你完全不關(guān)心。sort.Sort在壓縮最近臨被調(diào)用時(shí)可能看不出來(lái)但實(shí)際上它內(nèi)部用的是快速排序、堆排序和插入排序的混合方案專門為這個(gè)接口優(yōu)化的。一個(gè)最普通的例子給整數(shù)切片排序type IntSlice []int func (s IntSlice) Len() int { return len(s) } func (s IntSlice) Less(i, j int) bool { return s[i] s[j] } func (s IntSlice) Swap(i, j int) { s[i], s[j] s[j], s[i] } func main() { nums : IntSlice{3, 1, 4, 1, 5, 9, 2, 6} sort.Sort(nums) fmt.Println(nums) // [1 1 2 3 4 5 6 9] }你可能會(huì)問(wèn)標(biāo)準(zhǔn)庫(kù)不是已經(jīng)提供了sort.Ints和sort.Slice嗎為什么還要自己寫IntSlice沒(méi)錯(cuò)簡(jiǎn)單場(chǎng)景確實(shí)用不上sort.Slice一個(gè)函數(shù)就解決了sort.Slice(nums, func(i, j int) bool { return nums[i] nums[j] })但I(xiàn)nterface的價(jià)值不在簡(jiǎn)單場(chǎng)景而在復(fù)雜場(chǎng)景。當(dāng)你需要可復(fù)用的排序規(guī)則、需要多級(jí)比較、需要在不同數(shù)據(jù)結(jié)構(gòu)之間共享同一套排序邏輯的時(shí)候Interface的優(yōu)勢(shì)才會(huì)完全體現(xiàn)出來(lái)。2.2 理解 Less 是理解一切的關(guān)鍵Less(i, j int) bool的語(yǔ)義是i位置的元素是否應(yīng)該排在j位置的元素前面。這個(gè)“前面”不一定是數(shù)值小而是你業(yè)務(wù)上定義的前后關(guān)系。有個(gè)很重要的細(xì)節(jié)Less隱含了嚴(yán)格弱序的要求。什么意思你自己定義的比較規(guī)則必須滿足幾個(gè)數(shù)學(xué)上的性質(zhì)比如不存在“自己比自己小”的情況比如Less(a, b)和Less(b, a)不能同時(shí)為 true。如果你寫反了或者沒(méi)寫全排序結(jié)果會(huì)非常詭異。還有一條容易被忽略的規(guī)則當(dāng)兩個(gè)元素完全相等時(shí)Less必須返回false。如果相等還返回true排序算法會(huì)認(rèn)為“前者必須在后者前面”導(dǎo)致兩個(gè)相等的元素不斷交換位置輕則順序不穩(wěn)定重則影響性能甚至導(dǎo)致異常。2.3 一個(gè)關(guān)鍵認(rèn)知Less 的三個(gè)返回值拆解這里給你一個(gè)我常用的思考框架寫比較邏輯的時(shí)候把Less當(dāng)成一個(gè)“比較函數(shù)”來(lái)寫。這個(gè)思想來(lái)源于 C 語(yǔ)言的三方比較但是 Go 里L(fēng)ess的返回值只有 true 和 false。按照慣例比較函數(shù)會(huì)做三件事a b返回 true表示 a 排在 b 前。a b返回 false表示 b 排在 a 前。a b返回 false表示兩者等價(jià)順序無(wú)所謂。如果只有一個(gè)比較字段這就是全部邏輯。但多級(jí)排序就復(fù)雜在這里——副比較字段只有在主比較字段全相等的情況下才“說(shuō)得上話”。所以你的代碼邏輯應(yīng)該是if a.Primary ! b.Primary { return a.Primary b.Primary } return a.Secondary b.Secondary先做主字段比較能分出高低就直接返回分不出來(lái)再去做次字段比較。這正是多級(jí)排序的本質(zhì)。注意相等情況Primary相等不能簡(jiǎn)單返回false就結(jié)束你需要接著比較二級(jí)字段。很多新手在這里栽跟頭——一級(jí)字段相等時(shí)直接 return 了導(dǎo)致相等的元素不再根據(jù)二級(jí)字段排序。3. 多級(jí)排序的三種實(shí)現(xiàn)思路從“最笨”到“最優(yōu)雅”3.1 思路一Less 里嵌套多層級(jí)比較這是最直覺(jué)的寫法。一個(gè)訂單結(jié)構(gòu)體我們按“狀態(tài)升序、金額降序、時(shí)間升序、ID升序”四級(jí)排序代碼長(zhǎng)這樣type Order struct { ID int64 Status int Amount float64 CreatedAt time.Time } type OrderSlice []Order func (s OrderSlice) Len() int { return len(s) } func (s OrderSlice) Less(i, j int) bool { // 第一級(jí)狀態(tài)升序 if s[i].Status ! s[j].Status { return s[i].Status s[j].Status } // 第二級(jí)金額降序 if s[i].Amount ! s[j].Amount { return s[i].Amount s[j].Amount } // 第三級(jí)創(chuàng)建時(shí)間升序 if !s[i].CreatedAt.Equal(s[j].CreatedAt) { return s[i].CreatedAt.Before(s[j].CreatedAt) } // 第四級(jí)ID 升序作為最終兜底 return s[i].ID s[j].ID } func (s OrderSlice) Swap(i, j int) { s[i], s[j] s[j], s[i] }這種寫法有兩個(gè)好處。第一邏輯直白維護(hù)的人一眼就能看出排序優(yōu)先級(jí)。第二每一級(jí)都不需要什么花哨技巧就是基礎(chǔ)的比較判斷。但它的缺點(diǎn)也很明顯當(dāng)排序維度很多、條件邏輯很長(zhǎng)的時(shí)候這個(gè)Less方法會(huì)迅速膨脹。比如你有五個(gè)字段要排序每個(gè)字段還有升降序和空值處理規(guī)則這個(gè)函數(shù)很快就會(huì)寫到一百多行。而且不同實(shí)體之間的公共比較邏輯無(wú)法復(fù)用。3.2 思路二把比較器拆成獨(dú)立的函數(shù)既然一級(jí)一級(jí)的比較本質(zhì)上是一個(gè)“按照優(yōu)先級(jí)依次判斷”的過(guò)程我們可以把每一級(jí)的判斷邏輯抽出來(lái)讓代碼更清晰。先定義一個(gè)比較函數(shù)類型返回值用 int 表示三態(tài)負(fù)數(shù)表示小于0 表示等于正數(shù)表示大于。type CmpFunc func(i, j int) int然后寫一個(gè)通用骨架把一組比較器串起來(lái)type MultiSorter struct { len int swap func(i, j int) cmps []CmpFunc } func (m *MultiSorter) Len() int { return m.len } func (m *MultiSorter) Swap(i, j int) { m.swap(i, j) } func (m *MultiSorter) Less(i, j int) bool { for _, cmp : range m.cmps { if r : cmp(i, j); r ! 0 { return r 0 } } return false }接下來(lái)每一個(gè)比較器都是獨(dú)立的函數(shù)職責(zé)單一func cmpStatusAsc(s []Order) CmpFunc { return func(i, j int) int { return s[i].Status - s[j].Status } } func cmpAmountDesc(s []Order) CmpFunc { return func(i, j int) int { if s[i].Amount s[j].Amount { return -1 } if s[i].Amount s[j].Amount { return 1 } return 0 } } func cmpTimeAsc(s []Order) CmpFunc { return func(i, j int) int { if s[i].CreatedAt.Before(s[j].CreatedAt) { return -1 } if s[i].CreatedAt.After(s[j].CreatedAt) { return 1 } return 0 } }使用的時(shí)候按優(yōu)先級(jí)傳入ms : MultiSorter{ len: len(orders), swap: func(i, j int) { orders[i], orders[j] orders[j], orders[i] }, cmps: []CmpFunc{ cmpStatusAsc(orders), cmpAmountDesc(orders), cmpTimeAsc(orders), }, } sort.Sort(ms)這種方案好在哪里每個(gè)比較器可以單獨(dú)測(cè)試。你可以為cmpAmountDesc寫單測(cè)而不需要構(gòu)造整個(gè)排序場(chǎng)景。它還讓排序規(guī)則的增刪變得非常直觀——加一個(gè)規(guī)則往cmps里塞一個(gè)函數(shù)就行。但每次都要自己構(gòu)造MultiSorter仍然繁瑣而且len、swap要從具體類型提取代碼還是有些重復(fù)。更好的方式是泛型化把骨架固定下來(lái)。3.3 思路三泛型 鏈?zhǔn)秸{(diào)用寫在項(xiàng)目里最舒服的版本Go 1.18 之后有了泛型終于可以把上面這套骨架包裝得無(wú)比絲滑。先封裝一個(gè)Sorter[T]type Sorter[T any] struct { data []T cmps []CmpFunc[T] } type CmpFunc[T any] func(a, b T) int func NewSorter[T any](data []T) *Sorter[T] { return Sorter[T]{data: data} } func (s *Sorter[T]) Then(fn CmpFunc[T]) *Sorter[T] { s.cmps append(s.cmps, fn) return s } func (s *Sorter[T]) Len() int { return len(s.data) } func (s *Sorter[T]) Swap(i, j int) { s.data[i], s.data[j] s.data[j], s.data[i] } func (s *Sorter[T]) Less(i, j int) bool { a, b : s.data[i], s.data[j] for _, cmp : range s.cmps { if r : cmp(a, b); r ! 0 { return r 0 } } return false } func (s *Sorter[T]) Sort() { sort.Sort(s) }使用時(shí)NewSorter(orders). Then(func(a, b Order) int { return cmpInt(a.Status, b.Status) }). Then(func(a, b Order) int { return cmpFloat64Desc(a.Amount, b.Amount) }). Then(func(a, b Order) int { return cmpTimeAsc(a.CreatedAt, b.CreatedAt) }). Sort()需要配套一些通用的“比較原語(yǔ)”func cmpInt(a, b int) int { if a b { return -1 } if a b { return 1 } return 0 } func cmpFloat64Desc(a, b float64) int { if a b { return -1 } if a b { return 1 } return 0 } func cmpTimeAsc(a, b time.Time) int { if a.Before(b) { return -1 } if a.After(b) { return 1 } return 0 }這樣寫清晰、可復(fù)用、易測(cè)試而且鏈?zhǔn)秸{(diào)用讀起來(lái)就像聲明式排序規(guī)則團(tuán)隊(duì)協(xié)作時(shí)別人看調(diào)用代碼就能明白排序優(yōu)先級(jí)?,F(xiàn)在很多項(xiàng)目里我會(huì)優(yōu)先用這個(gè)方案不完全是因?yàn)椤案呒?jí)”而是它把業(yè)務(wù)邏輯和算法結(jié)構(gòu)徹底分開(kāi)后續(xù)想加一個(gè)排序維度不用碰排序算法那一層。4. 穩(wěn)定排序多級(jí)排序最容易忽略的“地基”4.1 為什么 sort.Sort 的結(jié)果會(huì)“閃跳”接著說(shuō)一個(gè)我在線 BUG 排查中遇到的真實(shí)問(wèn)題。當(dāng)時(shí)一個(gè)列表是雙層排序先按用戶等級(jí)降序再按注冊(cè)時(shí)間降序。理論上如果兩個(gè)用戶等級(jí)相同就應(yīng)該按注冊(cè)時(shí)間排。但我們當(dāng)時(shí)沒(méi)有寫注冊(cè)時(shí)間的比較邏輯等于說(shuō)等級(jí)相同的用戶順序是“隨機(jī)的”。當(dāng)時(shí)的現(xiàn)象是接口每次返回的數(shù)據(jù)順序都不一樣有時(shí)候用戶 A 在 B 前面刷新一下 B 又跑到 A 前面了。原因很簡(jiǎn)單——sort.Sort不是一個(gè)穩(wěn)定排序算法它不保證相等元素的原始順序。Go 里有一個(gè)專門的穩(wěn)定排序sort.Stable它用的是歸并排序會(huì)盡量保持相等元素的原始順序。但注意這里的“原始順序”是多級(jí)排序中的陷阱如果主排序字段相同的元素你想保留的“原始順序”是次要字段的有序狀態(tài)那必須讓這個(gè)狀態(tài)在排序前就已經(jīng)存在。4.2 穩(wěn)定排序的正確姿勢(shì)先排次級(jí)字段再排主級(jí)字段假設(shè)我們要實(shí)現(xiàn)“狀態(tài)升序、金額降序”。穩(wěn)定排序的做法是這樣的sort.Stable(OrderSlice, byAmountDesc) // 先按金額降序 sort.Stable(OrderSlice, byStatusAsc) // 再按狀態(tài)升序這種做法背后的原理是穩(wěn)定排序保證“相等”的元素保持之前的樣子。第一輪按金額排好序后所有金額有序。第二輪按狀態(tài)排序時(shí)如果狀態(tài)相同歸并排序不會(huì)去動(dòng)它們的相對(duì)位置于是金額的順序被保留下來(lái)了——相當(dāng)于自動(dòng)實(shí)現(xiàn)了次級(jí)排序。用代碼說(shuō)就是type byAmountDesc []Order func (s byAmountDesc) Len() int { return len(s) } func (s byAmountDesc) Less(i, j int) bool { return s[i].Amount s[j].Amount } func (s byAmountDesc) Swap(i, j int) { s[i], s[j] s[j], s[i] } type byStatusAsc []Order func (s byStatusAsc) Len() int { return len(s) } func (s byStatusAsc) Less(i, j int) bool { return s[i].Status s[j].Status } func (s byStatusAsc) Swap(i, j int) { s[i], s[j] s[j], s[i] }執(zhí)行順序很重要sort.Stable(byAmountDesc(orders)) sort.Stable(byStatusAsc(orders))幾次實(shí)際操作后我的體會(huì)是穩(wěn)定的多級(jí)排序?qū)崿F(xiàn)上少寫一個(gè)字段的比較邏輯而是反著實(shí)現(xiàn)——先排最不重要的字段最后排最重要的字段。這個(gè)方法在很多語(yǔ)言中都適用但 Go 程序員反而容易忽略因?yàn)?Go 的sort.Sort默認(rèn)不穩(wěn)定很多人沒(méi)養(yǎng)成用sort.Stable的習(xí)慣。4.3 什么時(shí)候用穩(wěn)定排序什么時(shí)候不用穩(wěn)定排序是好東西但它不是萬(wàn)能的。sort.Stable的時(shí)間復(fù)雜度在最壞情況下比sort.Sort差一些空間復(fù)雜度也更差。對(duì)于業(yè)務(wù)數(shù)據(jù)幾十萬(wàn)條以內(nèi)的排序幾乎感覺(jué)不到差別隨便用但對(duì)于上千萬(wàn)的數(shù)據(jù)量可能就需要評(píng)估一下了。另一個(gè)極端是如果你在Less里已經(jīng)寫全了所有的比較字段也就是說(shuō)任何兩個(gè)“不等價(jià)”的元素你都能定出前后那穩(wěn)定不穩(wěn)定對(duì)你來(lái)說(shuō)沒(méi)有區(qū)別——因?yàn)閴焊蜎](méi)有“相等元素”需要保序。這也是我在寫基礎(chǔ)排序規(guī)則時(shí)用的策略兜底字段一定要寫通常用一個(gè)唯一 ID 兜底徹底杜絕隨機(jī)順序。這樣即使未來(lái)有人改了排序規(guī)則也不會(huì)發(fā)生順序忽變的問(wèn)題。5. 升降序混排、空值處理、浮點(diǎn)數(shù)比較——容易被坑的三個(gè)細(xì)節(jié)5.1 升序降序混排不要用取反按金額升序是a.Amount b.Amount直觀的降序?qū)懛ㄊ莂.Amount b.Amount。但有些偷懶的寫法是!cmp(a, b)這個(gè)是大忌。!cmp(a,b)的邏輯等價(jià)于“a 不小于 b”意味著a b時(shí)也會(huì)返回 true。這破壞了 Less 的嚴(yán)格弱序性質(zhì)排序結(jié)果會(huì)錯(cuò)嚴(yán)重時(shí)還會(huì)導(dǎo)致交換邏輯陷入死循環(huán)。正確做法是寫清楚比較關(guān)系升序a b降序a b5.2 空值、零值一定要有明確的排序規(guī)則業(yè)務(wù)里經(jīng)常遇到字段為空的情況。比如訂單可選優(yōu)惠券、部分商品沒(méi)有折扣價(jià)。如果你不給空值定義一個(gè)明確位置那么排序結(jié)果會(huì)因?yàn)樽侄伪容^的不完整而隨機(jī)化。這種事在測(cè)試?yán)锖茈y發(fā)現(xiàn)因?yàn)闇y(cè)試數(shù)據(jù)一般都完整上線后用戶數(shù)據(jù)就露餡了。我的做法是空值統(tǒng)一排在后面。判斷先做空值處理再做人比較func cmpNullableString(a, b string, desc bool) int { aEmpty : a bEmpty : b if aEmpty bEmpty { return 0 } if aEmpty { return 1 } // a 是空排后面 if bEmpty { return -1 } // b 是空排后面 if a b { return -1 } if a b { return 1 } return 0 }注意即使排序方向是降序空值邏輯也應(yīng)該單獨(dú)處理不要因?yàn)檎w降序就讓空值跑到最前面。5.3 浮點(diǎn)數(shù)比較要慎用但排序里沒(méi)有關(guān)系很多新手在Less里寫浮點(diǎn)數(shù)比較時(shí)都習(xí)慣用判斷相等然后就開(kāi)始糾結(jié)浮點(diǎn)精度問(wèn)題“0.10.2 ! 0.3 怎么辦”但在排序場(chǎng)景里這個(gè)擔(dān)憂是多余的。排序比較只需要一個(gè)全序關(guān)系浮點(diǎn)數(shù)的直接比較就是全序關(guān)系。a.Amount b.Amount告訴你某個(gè)值是否排在另一個(gè)前面不需要你去判斷兩個(gè)浮點(diǎn)數(shù)“在數(shù)學(xué)上是否相等”。你不需要糾結(jié)“相差 0.0000001 算不算相等”的哲學(xué)問(wèn)題因?yàn)榕判蛞蟮氖莾蓚€(gè)值必須能分出前后或者等價(jià)。Go 的、本身就是嚴(yán)格的、確定性的比較用它們做排序完全沒(méi)問(wèn)題。唯一要注意的是NaN的存在。如果字段里可能出現(xiàn) NaN它跟任何數(shù)比都是 false這會(huì)導(dǎo)致排序不穩(wěn)定。你要么提前清洗數(shù)據(jù)要么在比較函數(shù)里顯式處理 NaN。5.4 通用比較原語(yǔ)參考表類型升序?qū)懛ń敌驅(qū)懛╥nt/int64a - b轉(zhuǎn)三態(tài)b - a轉(zhuǎn)三態(tài)float64if a b return -1等if a b return -1等stringstrings.Compare(a, b)取反時(shí)注意處理相等time.Timea.Before(b)a.After(b)bool!a ba !b6. sort.Slice 能替代 Interface 嗎說(shuō)說(shuō)我的選型標(biāo)準(zhǔn)現(xiàn)在很多人寫 Go 都用sort.Slice一句話就把 Less 寫完了比如sort.Slice(orders, func(i, j int) bool { if orders[i].Status ! orders[j].Status { return orders[i].Status orders[j].Status } return orders[i].Amount orders[j].Amount })這代碼簡(jiǎn)單、直觀對(duì)于一次性排序需求完全夠用。那sort.Interface的價(jià)值在哪我分享一下自己的選型標(biāo)準(zhǔn)。用sort.Slice的場(chǎng)景排序邏輯只用一次不需要復(fù)用。代碼量少局部看能得到很清晰的理解。項(xiàng)目的 Go 版本較低或者團(tuán)隊(duì)風(fēng)格就是偏好函數(shù)式寫法。用sort.Interface或者自封裝排序器的場(chǎng)景排序規(guī)則會(huì)在多個(gè)地方復(fù)用避免復(fù)制粘貼后改漏一處。需要仔細(xì)測(cè)試排序邏輯希望每個(gè)級(jí)別單獨(dú)測(cè)。排序規(guī)則是動(dòng)態(tài)的依賴外部配置或參數(shù)。想在排序前后加埋點(diǎn)、日志、統(tǒng)計(jì)集中在Swap里做反而更省事。有個(gè)實(shí)際體驗(yàn)有次我們需要根據(jù)用戶所在地不同的排序規(guī)則動(dòng)態(tài)生成組合比如 A 地區(qū)按“價(jià)格優(yōu)先”B 地區(qū)按“時(shí)間優(yōu)先”。用sort.Slice寫了一個(gè)巨大的閉包看起來(lái)頭都大了。后來(lái)改成封裝一個(gè)MultiSorter每個(gè)地區(qū)只需要配置自己的cmps列表規(guī)則一目了然。另外提醒一下sort.Slice的實(shí)現(xiàn)本質(zhì)上仍然是把閉包包裝成Interface它并沒(méi)有在性能上比特地手寫 Interface 有額外優(yōu)勢(shì)。它們都經(jīng)過(guò)sort.Sort或sort.Stable的快路徑性能幾乎沒(méi)差別。7. 實(shí)戰(zhàn)真實(shí)項(xiàng)目中如何落地一套可擴(kuò)展的排序?qū)?.1 定義排序方向的枚舉和可配置結(jié)構(gòu)實(shí)際項(xiàng)目中排序規(guī)則往往不是寫死在代碼里的而是來(lái)自 API 請(qǐng)求參數(shù)??蛻舳藗鱽?lái)“status,asc;amount,desc;created_at,desc”這樣的規(guī)則后端要能解析并動(dòng)態(tài)構(gòu)造成排序器。我建議設(shè)計(jì)一個(gè)排序配置結(jié)構(gòu)體type SortField struct { Field string Desc bool } type SortConfig []SortField排序器和具體結(jié)構(gòu)體解耦之后配置驅(qū)動(dòng)就很自然了func BuildOrderSorter(data []Order) *Sorter[Order] { s : NewSorter(data) for _, field : range config.SortConfig { // config 來(lái)自請(qǐng)求或配置中心 switch field.Field { case status: s.Then(cmpIntByFieldStatus(field.Desc)) case amount: s.Then(cmpFloatByFieldAmount(field.Desc)) case created_at: s.Then(cmpTimeByFieldCreatedAt(field.Desc)) default: continue } } s.Then(cmpIntByFieldID(false)) // 防止排序規(guī)則不足導(dǎo)致隨機(jī)順序 return s }這里兜底字段的重要性再次體現(xiàn)用戶傳了一個(gè)很隨意的排序規(guī)則哪怕只指定了一個(gè)字段ID 兜底也能保證順序穩(wěn)定。7.2 結(jié)合 context 實(shí)現(xiàn)可取消的排序排序本身很快但如果數(shù)據(jù)量極大比如百萬(wàn)級(jí)我們希望排序過(guò)程能響應(yīng) context 取消信號(hào)避免占用資源。不過(guò) Go 標(biāo)準(zhǔn)庫(kù)的sort.Sort不感知 context你只能在排序前判斷一次。如果真的要持續(xù)響應(yīng)取消信號(hào)需要自己實(shí)現(xiàn)帶取消檢查的排序算法這比較罕見(jiàn)一般不建議你這么做。對(duì)于絕大多數(shù)業(yè)務(wù)場(chǎng)景排序就是毫秒級(jí)或者幾十毫秒級(jí)不需要打斷。真的遇到超大集合更應(yīng)該考慮的是是不是可以把排序下推到數(shù)據(jù)庫(kù)畢竟數(shù)據(jù)庫(kù)的索引排序更劃算不要等數(shù)據(jù)加載到內(nèi)存再排序。7.3 排序性能調(diào)優(yōu)實(shí)測(cè)記錄我對(duì)三種實(shí)現(xiàn)做過(guò)一個(gè)不怎么嚴(yán)謹(jǐn)?shù)幕鶞?zhǔn)測(cè)試數(shù)據(jù)量 10 萬(wàn)條 Order方案耗時(shí)ns/op說(shuō)明sort.Slice手寫全字段 Less約 80ms最快無(wú)額外分配sort.Stable兩次排序約 120ms額外內(nèi)存分配較多MultiSorter泛型方案約 90ms與手寫基本持平略有閉包調(diào)用開(kāi)銷結(jié)論是泛型封裝的 MultiSorter 不會(huì)帶來(lái)明顯性能損失可以放心在日常項(xiàng)目中使用。如果數(shù)據(jù)規(guī)模不大幾千條這三種方案根本沒(méi)有肉眼可見(jiàn)的差別。真正影響性能的不是排序方案而是Less里的字段訪問(wèn)和數(shù)據(jù)分配。比如在比較函數(shù)中反復(fù)做字符串拼接、上級(jí)函數(shù)調(diào)用、取指針等操作都會(huì)拖慢排序速度。7.4 自定義數(shù)據(jù)結(jié)構(gòu)的排序特殊場(chǎng)景sort.Interface不止適用于結(jié)構(gòu)體切片。它的Len、Less、Swap可以映射到任意數(shù)據(jù)結(jié)構(gòu)上。比如鏈表排序。標(biāo)準(zhǔn)庫(kù)的sort.Sort要求隨機(jī)訪問(wèn)鏈表不滿足但你可以實(shí)現(xiàn)一個(gè)適配器type ListSorter struct { list *LinkedList } func (s *ListSorter) Len() int { return s.list.Len() } func (s *ListSorter) Less(i, j int) bool { a, _ : s.list.Get(i) b, _ : s.list.Get(j) return a.(int) b.(int) } func (s *ListSorter) Swap(i, j int) { a, _ : s.list.Get(i) b, _ : s.list.Get(j) s.list.Set(i, b) s.list.Set(j, a) }不過(guò)這依然是 O(n^2) 的獲取和賦值不如直接轉(zhuǎn)切片排序再重建鏈表。這里只是說(shuō)明Interface的抽象能力它不關(guān)心你的底層容器是什么只要你能實(shí)現(xiàn)三個(gè)方法就行。7.5 多字段排序與索引排序的取舍最后說(shuō)一個(gè)設(shè)計(jì)層面的問(wèn)題。如果數(shù)據(jù)經(jīng)常需要按多種不同的字段組合排序你會(huì)面臨一個(gè)選擇在內(nèi)存里每次動(dòng)態(tài)排序還是在維護(hù)數(shù)據(jù)時(shí)就按多個(gè)索引維護(hù)順序前者靈活但每次 O(n log n)后者高效但實(shí)現(xiàn)復(fù)雜。我的建議是業(yè)務(wù)量在幾十萬(wàn)條以內(nèi)直接內(nèi)存排序就好百萬(wàn)級(jí)以上且排序頻繁、實(shí)時(shí)性要求高就要考慮數(shù)據(jù)庫(kù)層面的多字段索引或引入專門的搜索引擎。不要用 Go 程序硬扛大規(guī)模全量排序這不合理。如果你發(fā)現(xiàn)排序成了系統(tǒng)瓶頸先想想有沒(méi)有辦法減少數(shù)據(jù)量或者能不能把排序下推而不是一味優(yōu)化Less函數(shù)。8. 踩坑實(shí)錄我見(jiàn)過(guò)的 sort.Interface 五大經(jīng)典問(wèn)題結(jié)合我自己和其他同事的實(shí)際經(jīng)歷整理幾個(gè)典型的坑你對(duì)照著排查肯定能少走彎路。8.1 Less 返回規(guī)則自相矛盾有人會(huì)把Less這么寫func (s Orders) Less(i, j int) bool { if s[i].Status ! s[j].Status { return s[i].Status s[j].Status } if s[i].Amount ! s[j].Amount { return s[i].Amount s[j].Amount } return true // 錯(cuò)誤 }當(dāng)兩個(gè)元素所有字段都相等時(shí)返回 true破壞嚴(yán)格弱序。排序可能在數(shù)據(jù)量大時(shí)出現(xiàn)異?;蛘呓Y(jié)果不穩(wěn)定。正確法則完全相等的元素Less 必須返回 false。8.2 忘了處理相等導(dǎo)致后續(xù)字段不生效最常見(jiàn)的問(wèn)題func (s Orders) Less(i, j int) bool { if s[i].Status ! s[j].Status { return s[i].Status s[j].Status } // 這里直接返回了后面的字段比較永遠(yuǎn)走不到 return s[i].Amount s[j].Amount }這種寫法其實(shí)是對(duì)的。但有另一種錯(cuò)法if s[i].Status ! s[j].Status { return s[i].Status s[j].Status } else { return false // 這里 else 分支提前結(jié)束了比較 }一旦狀態(tài)字段相等后面字段根本沒(méi)機(jī)會(huì)參與排序。排查技巧如果你發(fā)現(xiàn)排序結(jié)果只對(duì)第一個(gè)字段有效多半就是 Less 的邏輯提前返回了。8.3 Swap 寫錯(cuò)了位置導(dǎo)致數(shù)據(jù)被覆蓋func (s Orders) Swap(i, j int) { s[i] s[j] // 錯(cuò)誤直接覆蓋 }正確寫法是同時(shí)賦值func (s Orders) Swap(i, j int) { s[i], s[j] s[j], s[i] }這個(gè)看起來(lái)太基礎(chǔ)了但我真見(jiàn)過(guò)有人把Swap當(dāng)成“把數(shù)據(jù)搬過(guò)去”而不是“交換”。這種錯(cuò)誤通常不會(huì)報(bào)錯(cuò)只是排序結(jié)果完全不對(duì)排查半天。8.4 Len 返回常量排序不完整func (s Orders) Len() int { return 10 // 錯(cuò)誤寫死了 }這個(gè)錯(cuò)誤極少發(fā)生在業(yè)務(wù)代碼中但一些自動(dòng)生成的代碼或者帶有緩存的實(shí)現(xiàn)中可能出現(xiàn)。檢查技巧排序后如果發(fā)現(xiàn)數(shù)據(jù)只排了一部分先看 Len 是不是真實(shí)的集合長(zhǎng)度。8.5 指針切片和值切片搞混如果你持有的是[]*Order實(shí)現(xiàn)Less時(shí)就要用s[i].Amount而不是s[i].Amount后者根本編譯不過(guò)。這倒不是編譯錯(cuò)誤的問(wèn)題真正的問(wèn)題是——如果你在Less里直接修改了指針指向的對(duì)象的值排序過(guò)程中可能引發(fā)難以追蹤的數(shù)據(jù)競(jìng)態(tài)。比如func (s OrderPtrSlice) Less(i, j int) bool { if s[i].Amount 0 { s[i].Amount 999 // 絕對(duì)不能這么寫 } return s[i].Amount s[j].Amount }排序算法會(huì)反復(fù)調(diào)用Less在比較過(guò)程中副作用修改數(shù)據(jù)會(huì)導(dǎo)致不可預(yù)測(cè)的結(jié)果。Less 必須是純函數(shù)只讀不寫。9. 面試與八股之外Go 排序真正值得深挖的點(diǎn)最近 Go 面試題里很流行考排序但很多人都在背 sort 的底層算法細(xì)節(jié)比如“sort.Sort 什么時(shí)候用快排、什么時(shí)候用堆排、什么時(shí)候切到插入排序”。這些確實(shí)值得知道但如果面試官深問(wèn)一句“它們的切換閾值是多少”大多數(shù)人就答不上來(lái)了。我自己的經(jīng)驗(yàn)是八股記不住很正常重要的是理解設(shè)計(jì)模型。我來(lái)幫你梳理一下 Go 的sort包內(nèi)部機(jī)制sort.Sort適用于大多數(shù)情況使用快速排序pdqsort 變體Go 1.19 之后切換為 pdqsort在數(shù)據(jù)基本有序或長(zhǎng)度小于閾值時(shí)切換到插入排序當(dāng)分區(qū)遞歸深度過(guò)大時(shí)切換到堆排序保證最壞情況 O(n log n)。sort.Stable使用歸并排序穩(wěn)定的開(kāi)銷是額外的內(nèi)存分配。對(duì)于已經(jīng)有序或者長(zhǎng)度很小的切片它也會(huì)走插入排序快路徑。sort.Slice內(nèi)部其實(shí)就是把閉包轉(zhuǎn)換成Interface再交給Sort。知道這些的好處是你能解釋清楚“為什么大多數(shù)業(yè)務(wù)排序直接用sort.Slice就夠了”同時(shí)也能解釋“什么時(shí)候你自己實(shí)現(xiàn)Interface會(huì)更好”。面試官更看重的往往是后者——你的工程判斷力。提示Go 1.19 之后的各種排序算法切換閾值并非常量在不同規(guī)模的切片上表現(xiàn)略有不同。如果你在寫底層庫(kù)且追求極致性能不要依賴于這些內(nèi)部閾值直接用sort.Sort就好。10. 把這些經(jīng)驗(yàn)收進(jìn)工具箱多級(jí)排序用sort.Interface實(shí)現(xiàn)歸根結(jié)底就是三句話在Less里按字段優(yōu)先級(jí)逐個(gè)比較能比較出結(jié)果就直接返回不能就繼續(xù)下一級(jí)。要善用穩(wěn)定的兩次排序方案——先排次級(jí)字段再排主級(jí)字段能得到同樣的多級(jí)效果而且代碼更簡(jiǎn)潔。無(wú)論如何都要加一個(gè)唯一字段兜底確保任何情況下排序結(jié)果都是確定性的。我個(gè)人在實(shí)際項(xiàng)目里的體會(huì)是多級(jí)排序的難點(diǎn)從來(lái)不是“怎么調(diào)用 sort 包”而是“你的業(yè)務(wù)規(guī)則是否被準(zhǔn)確地表達(dá)成了嚴(yán)格弱序”。寫排序代碼的時(shí)候把字段的相等、空值、升降序處理想清楚比背誦任何排序算法的細(xì)節(jié)都有價(jià)值。如果你正被多級(jí)排序折磨建議先把你所有的排序字段列成一個(gè)表一行一個(gè)字段標(biāo)上優(yōu)先級(jí)和升降序方向。然后從上到下把表翻譯成Less代碼或者翻譯成一行行Then(...)調(diào)用。這塊表寫清楚了代碼基本不會(huì)錯(cuò)。最后別忘了一個(gè)好東西給排序邏輯寫測(cè)試把每個(gè)字段單獨(dú)出測(cè)試用例特別是“字段值相等”的情況——這是最容易出錯(cuò)、又最容易被漏掉的地方。最后再分享一個(gè)小技巧我在團(tuán)隊(duì)里一直提倡排序規(guī)則涉及業(yè)務(wù)語(yǔ)義時(shí)不要直接在Less里寫裸的比較符號(hào)而是給比較邏輯起一個(gè)有意義的名字比如isHigherPriority、shouldComeBefore。這樣過(guò)了一個(gè)月再回頭改代碼你不需要重新揣摩那幾行if想表達(dá)什么直接看方法名就明白了。這個(gè)習(xí)慣幫我省了數(shù)不清的排查時(shí)間。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
国产熟女完整版中字| 野狼激情网| 久久久久久人| 日日干男人的天堂| 天堂资源欧美| 99国产精品久久久在线播放| 天天日天天插| 91动漫操逼视频| 久久97| 久草热制服丝袜在线观看 | 日日黄色三级网站| 极品极品色影院| 亚洲图片偷拍欧美| 亚州熟妇精品| 欧美影音在线| 国产美女精品| 三上制服丝AV| 在线综合 亚洲 欧美中文字幕 | 国产60区。| 五月丁香啪| 爱射综合| 久久发布国产伦子伦精品| 五月天婷婷小说| 偷窥自拍亚洲天堂网爆| 亚洲人成色9999精品久久| 99精彩视频| 中文字幕在线免费观看视频| 超碰 av 女人天堂| 夜夜嗨一区二区三区三州加勒比| 1000午夜黄色| 久久精品操| 日夜尻逼网| 亚洲国内精品成人不卡| 97视频免费在线| 日日日色色色色色| 久久精品噜噜噜成人看免欧美大片| 亚洲综合九| 日韩精品99久久久久久中文字幕| 久久久久久久久九九久孕交| 一区二区三区蜜桃成人撸久久东京热| 午夜色婷婷| 日韩欧美俄罗斯A片| 国产亚洲精品美女久久久久久2021| а√天堂资源官网在线资源| 啪啪资源网| 天堂中文资源在线bt| 国产黄色影片在线观看| 性开放中文AV高清无码免费看| 一本大道不卡一二三区| 欧洲熟妇xxXx欧美老妇裸体| 日日夜夜干| 九久9热| AV在线资源| 超碰97久久国| 中文字幕在线免费观看2| 人妻一二三区| 嗯嗯啊在线视频| 亚洲免费精品一区| 91狼人| 中国少妇啪啪视频| 后入日本1234| 欧美躁死她一区二区| 蜜臀久久久国产| 亚洲激情网一二三四区| 国产黄色动态精品| 亚洲天堂 视频你懂的| 天美传媒av在线| 好爽免费视频,| 亚洲男人天堂2017| 一二区在线观看视频| 噜噜噜亚洲精| 中日无幕一二三四区| 亚洲国产综合图区中文字幕| 一线黄色免费性爱片| 操逼视频亚洲| 欧美亚洲首页| 超清福利精品视频在线| 99这里只有精品| 久草在| 97在线播放| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区 | 国产一区二区a毛片| 7777欧美成是人在线观看| 日日狠狠久久偷偷色综合免费| 亚洲色图加勒比| 97亚洲国产| 97干97色| 一级毛片久久久久久久女人18| 国产精选三级在线观看| 安徽熟妇视频| 91情色在线| 国产精品亚洲天堂网址| 黑操B| 久久一本大香蕉 | 97碰在线视频| 中文字幕午夜精品久久久| 999精品久久久久久久| 性在久久久久久| av国产无码| 久操不卡视频| 91精品国| 亚洲色综合| 99国内熟女露脸视频| 丰满人妻区一区二区三| 五月丁香啪| 好爽要喷了| 18禁免费视频| 中文字幕、久久精品国产2020、久久综合久久自在自线精品自、亚洲 | WWW黄片COM| 精品国产99| 免费视频在线一区二区不卡| 青青爽| 躁躁躁日日躁2020| 丁香六月婷婷| 上特色A在线| 六月激情网| 久热精品在线| 骚乳在线| 丝袜美腿制服人妻二区中文字幕| 国产成人精品一区| 99综合免费视频| 超碰九九| 青青草日韩无码| 亚洲欧洲日韩中文字幕一区| 激情婷婷| 被男人吃奶很爽的毛片| 超碰97首页| 午夜福利免费精品视频| 欧美在线大香999| 国产成人自拍视频在线| 深夜激情| AV 少妇 人妻 偷拍| 日日干日日摸| 青青草原狼av| 久久久久久久伊人精品| 狠狠色丁香| 日韩在线观看三级电影| 亚洲瓯美色图| www.91理论| 久久久青草青青国产亚洲免观精品高清完整版_97久久综合区小说区图片区,国精品 | 狠狠中文字幕| 免费观看网黄| 97AV在线免费观看| 九九黄色网| 久久久97| 亭亭在线资源| 国产伦精品免编号公布| 免费一级精品啪啪视频| 亚洲第一页综合在线| 久久9视频| 免费成人自拍视频在线| 97精品中文字幕| 97福利视频| 五月天我淫我色av| 99re在线视频这里只有精品| 欧洲中文字幕| 多乙久久久久久| 伊人九九九| 亚洲 欧美 小说| 国产美女自拍AV| 亚洲色图欧美另类在线| 婷婷五月天小说| 天天操人人操狠狠插| 午夜精品久久久久久久99| 91亚洲人电影| 偷窥自拍亚洲天堂网爆| 国产视频一区二区三区在线免费观看| 夜夜做夜夜爽精品视频| 色女99一级片在线观看| 99热超碰在线| 欧美日韩国内不卡| 久久精品午夜国产亚洲AV无码| 亚洲中文字幕一区| 天美传媒在线一区| 久久久久久久久久久久久久久乱码| 久久91精品国产9丨久久分亭| 亚洲熟妇A V黑人| 日亚韩精品视频二区三| 九九九九九九九九九九九蜜桃| 97超碰69| av优播| 亚洲第一在线视频| 岛国黄色短视频| 超碰精品国产无码| 97视频网站| 96国产精品| 加勒比av官网在线| 久久久久久久久久精| 91亚洲不卡一区| 欧美色五月| 日本五十路熟女一区二区| 欧美呦呦性爱| 蜜乳Av成人片网站| 91c色| 欧洲综合无码| 澳门黄片一香蕉视频| 婷婷五月天激情四射| 国产中文字幕在线| 色香91| 黄久在线| 久久中文字幕女同性恋一区| 97就爱干| 精品一区二区2| 亚洲欧美日韩电影网站一区 | 一区二区首页| 青青草视频久久久久| 青草视频在线看看看看看看看看看| 亚洲av无线观看| 久久99人妖视频国产| 国产亚洲中文不卡二区| 搡老熟女老女人老熟妇免费视频| 人人天天欧洲| 亚洲熟女乱综合一区二区三区| 欧美色涩| 亚洲欧美国产va在线播放频| 久久免费99精品久久久久久| 日本狂喷奶水在线播放212| 日本日逼高清| 不卡免费av在线播放| 久久男女激情视频网站| 任你草| 老女人爆菊| 亚熟在线| 国语精品av| 日本熟妇浓毛hdsex| www.亚洲成人一区| 青娱乐久久艹| 亚洲欧美九九九| 97国产天堂岛| 久区视频| 91精品久久久久五月天精品| 久久精视频美日韩在线视频| 黄色大片一区二区密桃丝袜| 蜜臀色乳| 日本欧美不卡| 久久伊人亚洲AV无码网站| 色狠狠 - 百度| 日韩成人电影AV| 人妻少妇精品一区二区三区| www.高清无码诱惑一区.com | 黄色片大香蕉| 亚洲天堂第一页| 狠狠干妹子| 阿姨一区二区免费视频-高清正片西瓜视频下载app-T450AV | 日韩一级二级三级在线不卡观看完整| 人人操人人色人人摸| 欧美日韩国内不卡| 日韩紧密久久| 少妇熟女一区二区三区| 亚州操逼图| 色噜噜综合在线| 中文字幕人乱码中文字的预防方法| 伊人在线大香蕉二。| 神马麻豆福利院| 搡老人老9丨女老熟人| 激情九月婷婷| 国产欧美日产一区二区三区 - 国产欧美日 | 久久亚洲日韩熟女精品| 99这里只有精品国产| 99热9| 亚洲中文电影| 亚洲 欧美 精品专区 极品| 国产一区二区在线电影| 性性久久| 超碰色男人操熟女| 九九九午夜| 蜜桃AV天堂| 综合影视国产无码| 久操大香蕉超碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰 | 熟妇熟女视频一区二区三区| 日韩精品午夜操呦呦不卡影院| 囯戸精品高潮呻吟旡码| 夜夜操2028| 日本高清一本二本免费不卡| 日韩性爱再线视频| 亚欧美综合| 操逼免费视频无码国产| 97干色天堂| 精品一级毛片在线观看| 农村妇女一级二级三级视频| 蜜臀99久久精品| 3028国产精品| 欧亚揄拍偷拍精品视频| 少妇啪啪自拍| 青青草好吊| 中文字幕亚洲永久精品| 超碰久久网| 人人看欧美性爱| 欧美老妇女内射网址| 国产精品96| 99综合免费视频| 99热在线只有精品| 激情综合五月天| 亚洲图片视频小说| 熟妇在线视频一区二区| 免费视频97| 欧洲色色| yaouchengrenav| 又大又黄国产| 欧美中文字幕日韩在线| 女人的天堂大香蕉网| 无码操逼视频一下| 精品96久久| 色色色天美视频| 少好三P| 97任你吞精| 欧中美三级一区二区三区| 激情五月综合| 少妇一级无码精品| 九九自拍伦理| 天美传媒国产原创中文字幕亚洲欧美另类 | 深夜激情| 色噜噜综合在线| 91久久九九精品国产综合| 亚州综合电影| 网页导航五月天免费一二三区 | 久久乐| 国产精品高潮久久久无码| 老熟女熟妇| 大香蕉免费乱伦视频| 亚洲第一男人天堂| 欧美日韩情色一区二区| 久久久久久一日韩字幕无码| 色欧美色交综合| A V少妇特黄三级| 香蕉黄色一级视频| 少妇无码999| 久久一二三四不卡| 五月丁香婷婷色| 国产黄色视频久久| 日比av无码| 国产精品肉丝自拍| 人人操人人大香蕉| 国产综合色精品在线观看| 久久99精品国产| 久久性爱城| 超碰在线一区二区| 久久亚州大香蕉| 精品网站9999| 99久久久无码国产精品性男| 国产午夜福利专区综合| 天堂亚洲精品| 久色99999| 天无日色综合| 日本九九九九| 370p日韩欧美亚洲精品| 91精品国产91久久青草 | 日本超碰色精品| www.色五月| 国产一区在线观看无码AV| 啊啊啊慢点| 高清肉丝中文无码| 亚洲熟妇无码一区二区三区| 色色五月婷| 欧美日产国产在线成人第一区| 欧美色另类| 欧美在线视频播放| 欧美中字二区| 精品无吗久久| 爽爽歪在线视频| 日韩亚洲Av人人夜夜澡人人爽| 亚洲在线| 神马九九| 大香蕉懂9| 亚洲精品欧美专业| 刺激性视频黄页| 久久久久久久九九九九九九| 91免费看中出视频| 日韩欧美三级| 超碰 国产熟女精品一区| 亚洲天堂色图| 欧美在线官网| 人妻天天爽夜夜爽爽| 97碰在线视频| 久久久激情| 婷婷丁香成人| 综合色99| 六月婷婷综合| 91爽啪| 婷婷五月天激情网| 9/A片 | 欧美性爽xyxOOOO| 日韩综合无码一区久久92| 天天拍夜夜| 欧美色网络| 精品九九九九九九| 国产一区二区三区高清视频| 26uuu久久| 欧美v亚洲v综合v国产v妖精| 欧美日日操| 乱伦av麻豆| 天堂中文资源在线bt| 国产精品自拍欧美在线| 无遮挡猛进视频免费无限观看| 去干网最新版| 亚洲。日韩。欧美| 一直超碰| 亚洲第一视频 欧美风情 日韩| 综合亚洲网| 91综合中文字幕| 久久国产AⅤ| 亚洲国产欧美另类自拍| 立川理惠无码一区二区| 久久,精品一二三| 欧美专区在线| 人妻内射一区二区在线视频| 性感美女91影视| 综合激情五月天| 欧美日韩丝袜 | 人人搞人人插人人操| 18啪啪手机免费性爱| 无码高清专| 啊啊啊啊好疼| 91中文字幕制服丝袜免费视频| 日韩人妻一二三区视频| a片 xxxx受爽视频| 久久久久亚洲?V片无码V| 日本操逼视频在线| aaa一级黄片| 青青操97| 国产精品白丝AV| a级免费在线观看| 国产白嫩漂亮KTV在线| 9久久精品| 久久黄色网址| 99福利社| 国产成人精品必看 | 美欧老女人97| 欧美乱欲| 黄色性爱网网| 国产农村妇女精品一| 亚洲精品天天影视综合网 | 999久久久免费精品国产牛牛| 熟女五十路一区二区三| 日本美女性生活久久久久久久 | 人妻99p| 中亚av| julia ann久久| 永久电影三级在线观看| 丁香婷婷久久| 99热国产精品| 国产一区二区三区久久久精品| 欧美日综合| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师 | 激情婷婷丁香| 成人无码在线视频网站| 国产91美女高潮| 大屁股熟女一区二区三区| 黄骗免费网站| 亚洲 欧美都市激情| 欧美综合自拍亚洲综合图| 黄色大片免费在线| 一区久久久二区| 欧美碰碰综合色| 操逼片中文| 欧美亚洲涩涩| 日本不卡高清视频| 欧美日韩亚洲五月天婷婷| yiqicaoav| 91蜜臀在线久久久久| 精品免费囯产一区二区三区| 欧美亚洲日本视频久久久| 国产精品久久久久久久久久久久久久久久| 香伊人在线| 蜜桃在线观看一区二区三区| 亚洲精品国产精品成人| 色婷婷在线视频精品导航| 97九色| 天天操天天射青青草| 69天堂| 久久国产99精品72福利 | 女优视频第10页| 超碰色老头| 开心五月激情网| 夜夜高潮夜夜爽夜夜爱爱一区 | 91欧美www| 日本久久精品| 欧美v日韩v亚洲v最新在线| 性爱动态120秒| 天天色图| 好舒服视频| 牛牛aV| 91美女片在线| 99久久无色码| 日韩综合无码色欲vv| 极品AV网站在线观看| 在线观看岛国有码| 久久亚洲一区女同性恋中文字幕 | 中文字幕一区二区三区50路| 欧美 亚洲 大香| 亚洲第一狼人丝袜美女另类 | 精品一区二区综合熟妇| 亚洲色天堂九9| 啊啊啊啊嗯嗯嗯用力好爽 | 久久九九一区二区三区成人| 天天色,天天干,天天干| 中文字幕一区二区无码成人| 中文字幕视频2区| 乱伦av国产| 3P丝袜熟女 色综合| 伊人色综合超碰| 男女激情黄色网址| 91色综合| 欧美性五月| 国模限制级电影| 一类无码操逼视频| 亚洲欧美清纯| 91色色综合| 99热这里| 久久久国产亚洲精品系列| 蜜臀久久99精品久久久久久成人小说 | 啪啪啪大香蕉| 日韩激情电影中文字幕| 日本 情色 1区2区3区| 亚洲色图久久成人| 无码日韩网站| 亚洲免费成人在线高清无码视频| 加勒比99999| 中文字幕精品久久久久人妻红杏ⅰ| 99久久99久久综合| 亚洲蜜乳av| 国产精品999aaa| 老司机福利社视频在线观看| 操逼内射干逼白丝91| 婷婷五月色| 99re公开精品免费视频| 青娱乐福利99| 九热中文字幕| 日韩欧视频| 亚洲色图第四色| 最新中文字幕av| 九九热精品免费视频| 成人av动漫在线观看| 欧美精品日韩久久久九| 白丝被操91| 中文字幕一区二区视频在线观看 | 成人美女av| 精品久久久久久AV无码| 一区在线精品中文字幕| 人妻丝袜日本| 五月天伊人网| 欧美色综合网| 人妻久久| 大香蕉狠狠爱| 97超碰9| 超碰97日韩| 97精品全部| 色香网| 久久蜜桃一区二区| 久久97视频| 亚洲第一视频 欧美风情 日韩| 精品乱码在线观看| 制服丝袜第二页| 日韩欧美中文字| 神马久久69| 青娱乐手机日韩在线视频| 先锋音影AV| 国产精品亚洲日韩骚欢乐谷最新地址发布页huanieguty性屋娱乐妖精视频 | 永久电影三级在线观看| 老司机午夜精品视频| 日韩综合无码一区久久92| 久久久性| 国产精品ⅴ无码大片在线看.| 麻豆视频国产一区二区| 91丨九色丨国产丨人妻在线| 午夜视频好爽啊| 韩国黄片aaaa| 亚洲欧洲网站免费观看| 久热这里| 粘花网06av视频| 久久久久久中文版| 啊啊啊啊好大好硬啊啊啊啊啊| 69丨亚洲丨精品丨入口免费播放| 9 1超碰九色| 欧美色综合网| 国产精品黑人一区二区三区| 手机在线A片| 韩国一级婬片A片AAAAA| 老色69| 久久久久亚洲一区女同性恋中文字幕| 超碰午夜| 超碰91在线| 香蕉久久AⅤ...| 国产日韩欧美三级片| 色综合美国| 久久一二三四五六七八九区区| 男人的天堂久久狠| 青青草好吊色| 91在线视频观看国产| 日韩啪啪网| 久久99手机免费视频| 国产热av| 免费A片三p视频| 亚洲黄色a级片| 日韩草久视频| 美女丝袜激情小说| 91操操操操| 影音先锋中文字幕日本好一区二区| 亚洲激情综合| 成人片视频| 无码人妻1727| 国内毛片国产专区二| 超碰超碰95| 欧美草草| 青草草免费网站av| 人妻激情偷乱视频一区二区三区| 综合天天网| 91 丝袜在线播放| 亚洲精品中文字幕一区在线视频| 亚洲aw毛茸茸在线 | 国产精品久久久三级无码| 九一综合精品视品av| 国产自偷| 97人妻免费中文字幕| 黄色乱论网站| 高清无码人妻久久久一区二区三区aⅴ| 黑人精品XXX一区一二区| 国产亚洲在线观看| 男女性扦B| 日本人妻伦在线中文字幕| 色色99| 激情四射婷婷六月天| AⅤ片水多多| 亚洲男人天堂2019| 91久久国产精品| 精品国产乱码久久久久久口爆网站| 中文字幕亚洲欧美在线不卡| 日韩小电影| 91碰碰碰| 夜夜久久久| 久久久国产三级黄色片| 少妇高潮喷水无套久久久久久| 国产成人拍国产亚洲精品| 欧美图片偷拍| 啊啊啊操死我| 欧美综合站| 人妻精品一区二区| 婷婷亚洲天堂| 97碰碰色| 日韩三四五区| 久久久久久精| 天天淫人人妻日日色| 97亚洲精品| 天综合网| 日本操逼无码| 久久一二三四不卡 | 青青草久久| 亚洲天堂7777| 色九九久九九| 天天操夜夜操| 欧美日韩1234| 一区麻豆 高清中文字幕| 亚洲国产美女久久久久| 超碰97男人| 国产精品无码久久久久2025| 日本不卡二三区| 国产精品人妻熟女aⅴ| 亚洲成人妻日韩在线| 久久av成人无码免费| 美女黄码视频午夜| 日本123区操B视频| 热99re69精品8在线播放| 日本超碰在线国产一区| 亚洲自拍偷拍视频在线| 国产黄色动态精品| 日韩中文字幕精品一区在线| 亚洲污污网站| 无遮挡猛进视频免费无限观看| 成人精品久久| 青青操97| 国产高清26uuu| 久久精品噜噜噜成人看免欧美大片| 9999久久久久| 狠狠操狠狠操操| www.AV有限公司一区| 亚洲成人美女无吗| 婷婷五月天激情四射| 久久9亚洲| 国产一区二区a毛片| 青青草综合在线| 日日狠狠久久偷偷色综合免费| 久久亚洲日韩熟女精品| 操91| 久久欲| 国产热av| 亚洲经典啪啪| 熟女少妇视频| 亚洲综合99999| 欧美婷婷| 国产Aα| 欧洲精品欧洲精品| 91男女啊啊啊| 岛国片在线观看视频亚洲| 一区在线精品中文字幕| 久久熟女嫩草成人片免费 | 亚洲成人性爱网站在线播放| 欧美色91| 欧美 亚洲 综合 制服 另类| 97天天摸天天碰| 国产高清成人mv在线观看| 78久久| 极品一区二区三区免费| 日本久操视频| 精品伊人久久久大香线蕉小说| JuliaAnn丝袜熟女系列| 欧美色色人| 午夜福利久久久噜久噜久久综合| 日韩激情啪啪| 超碰99在线| 亚洲女人毛茸茸91| 亚洲激情色片| 亚州操操穴网| caorenqi shipin| 激情综合网五月婷婷五月天| 久久国产熟女影院| 天天综合-91入口| 中文字幕福利视频一区二区三区在线观看| 亚洲综合图文| 亚洲国产一区二区三区在线| 四虎影院成年人片| 国产人伦a片信息免费片| 亚洲一区二区三区春色| 97干在线视频| 抽插亚洲无码| 精品熟妇视频一区二区| 亚州图片第一页| 国产精品视频播放| 毛片17S| 欧美中文字幕男人天堂久久精品| 亚洲九九夜夜| 五月丁香色婷婷| 欧美丰满熟妇XXXX性ppX人交| 久久东京伊人一本到鬼色| 在线观看不卡一区二区三区| 日韩性爱长视频免费| 天美传媒AV在线播放| sewuyueav| 欧美精品一二三| 加勒比海人人操超碰在线| 国产久9| 亚州,欧美在线| 精品国产乱码久久久影院| 亚洲人精品久久久| 婷婷人妻激情| 搡老女人老熟女91老熟女综合网| 超碰在线91| 99999亚洲| 97超碰精品| 欧美性生活男人的天堂| 老熟女搡BBBB搡BBBB视频| 天天视频黄| 欧美呦呦性爱| 久久一区二区高清免费| 日韩精品怡红院| 超碰中文字幕人妻草一区| 人人爽夜夜操| 天天影视射综合网| 国产精品第一页国产大屁股视频免费区i| 婷婷另类小说| 亚洲无限观看| 啊啊啊啊嗯嗯在线久久久| 超碰97男女| 欧美91精品国产自产| 99热| 成年人三级黄色片视频| 人人操人人插人www| 日韩成人大片一区二区| 五月天综合在线| www四虎| 国产a级精品| 蜜桃精品视频一区二区三区| 久久97视频| 国产综合日韩伦理| 狼狼色丁香久久婷婷综合五月| 1024人妻熟女一区二区三区| 狠狠操狠狠插| 天天综合欧美综合| 国产又大又粗又长视频| 加勒比伊人| www.黄色在线| 91丨国产丨白浆| 综合97久久| 中文视频在线观看| 操逼啊啊啊91| 97日本超碰综合| 欧美在线视频播放| 婷婷爽人人婷婷爽视频| 日韩一区二区高清在线观看的| 亚洲精品亚洲人成人网| 亚洲天堂另类小说男人| 国产自偷| 99国产在线 精品 视频| 五月天激情婷婷| 九九av| 国产精品久久久吖| 9久久精品| 成人一区二区三区四区| 久久精品黄色| 久久免费精品视频免一| 91色黑人少妇| 9Ⅰ超碰| 日韩丰满熟妇| 久久久熟妇熟女国产| 欧美精品激情| 日韩去日本高清在| 久久久男人的天堂| 九九视频黄色片| 99亚亚热| 97欧美综合网| 日本精品成人无码| 中文一区二区| 在线看的av| 久久av网| 国产辣妈在线视频福利| 极品五月天噜噜| 97超级久久| 欧美性爱在线无码| 亚欧美色图| 亚洲成a人片在线观看中文!!!| 熟啊v色欧美热| 熟妇乱伦一区二区| 亚洲情色婷婷五月天| 亚洲性高潮| 激情看片网站| 色哟哟av| 色噜噜人妻丝袜a∨先锋影 | 麻豆亚洲Av成人无码一区精品| 蜜汁欧美| 婷婷久久五月| 久久久久久十| 九九黄色网| 91精品国| 婷婷中文字幕| 欧美色图 色综合图| 丁香六月婷婷久久综合| 超碰在线日韩一区| 99热成人| 欧美一二三| 国产人伦精品一区二区三区| 国产主播福利| 蜜臀人妻少妇久久在线观看| 摸奶性爱视频网站在线免费播放| 日韩精品人妻系列无码天堂| 天堂v无码免费视频| 中文字幕丝袜人妻| 久久久一区二区三区三州| 超碰这里只有精品| 国产AV毛片| 97资源站国产精品| 91粉芽高清在线一区二区| 97欧美精品| 动漫片子网站3黄| 九月激情婷婷| 玖玖超碰熟| 婷婷激情五月综合| 欧美组图日韩亚洲中文字幕| 97露脸精品丝袜| 日日摸夜夜夜夜爽| 亚洲天堂久久| 在线观看十八禁| 高清无码一区二区三区| 久久9999 | 亚洲中字幕日本一区二区三区| 亚洲丝袜色图| 日韩欧美亚洲一区二区三区影院| 91无码人妻精品一区二区三区蜜桃| 五月丁香久久| 91人精品妻入口| 久久久内射良家| 夜夜嗨一区二区| 国产精品久久久久久照片| 久久久久婷婷精品av电影| 91精品久久久久久77777| 蜜桃久久一区二区| 超碰天天操| 91蜜桃婷婷狠狠久久综合9色| 日本国产欧美一区三区二区| 亚洲黄色网址| 亚洲日韩AV视色| 亚洲欧美自拍偷拍| 97综合在线| 内射黑丝袜| 欧美v日韩欧亚洲电影天堂色诱,国产传媒| 日本一区二区三区午夜观看| 男人天堂最新手机版在线青青草| 色婷婷aV一区二区三区麻豆综合| 国产精品无码在线| 女性喷水高潮在线观看| 国产深喉| 97精品第3页| 九九在线视频| 亚洲一区二区精品福利| 欧美大香蕉久| 亚洲 日本 不卡| 大香蕉在线免| 青草地一本线一区二区三区| 一直超碰| 亚洲最大的黄色电影网站。| 偷窥自拍亚洲天堂网爆| 国产一区二区三区久久久精品| 婷婷人妻激情| 天堂网 主播 亚洲| 久久天天躁日日躁狠狠躁| 97人人操人人干| 国产AV无码AV| 国产久久成人| 日本人妻最新在线中| 亚洲图片视频小说| 亚洲色图综合网| 色婷婷蜜臀av| 日本在线不卡123| 综合色啪| 最新国产亚洲精品精品国产亚洲综合| 人人玩人人添人人澡免费| 大肥女高潮bbwbbwhd视频| 丰满人妻-区二区三区免费看| 久久同城AV| 狠狠图片青青草| 丰满少妇一区二区三区专区| 99激情| 日本色婷婷| 激情综合亚洲| 综合色色网| 人人插人人搞人人操| 欧美日韩国内不卡| 爱av免费| 日韩欧美国产高清视频| 久久国内| 亚洲无码久久久久久久| 国产综合网站在线播放| 国产麻豆福利av在线播放| 精品成人动漫一区二区| 日本操色导航| 美女尤物人人操| 国产精品久久99日日| 51久久夜色精品国产麻豆| 天天上日日上日韩精品| 亚洲色婷婷久久91| 狠狠色伊人亚洲综合网站色| 国产精品白领在线观看| 精品日韩人妻视频| 日韩黄色av中文字幕| 无遮挡一级毛片视频免费的| 91丨九色丨国产丨人妻在线| 牛牛操视频逼| 性影在线视频| 激情视屏国产乱伦强奸| 爱媛媛久久国产福利| AV电影在线播放| 国产精品老熟女一区二区| 好湿好紧好爽 视频| 日本熟人妻中文字幕在线|...久久国产精品-国产精品_日本一区二区三区中文字幕 | 欧美色就是色| 翔田千里A片一区二区| 一级做a爰片性色毛片久久| 操B视频日韩无码| 成人a大片在线观看| 黄网色一区二区三区四区精品| 日韩免费性爱视频在线观看| 91neishe| 中国黑人三级片网站上区| 夜夜 中文视频rt| 大香蕉一人| 亚洲色图欧美色图另类图片| 东京热视频网| ?亚洲伊人伊成久久人综合网| 亚洲成人AB| 2017大香蕉| 91精品女厕偷拍视频| 在线国产一区二区av| 裸体美女国产免费久久久网站| 国内精品久久国产,www香蕉久久五月丁香,亚洲欧美日韩精品永久在线,日本精品一 | 久久九九综合| 97久久超碰国产网站| 安微少妇操BBB| 亚洲加勒比久久日本道| 青椒国产97在线熟女| 啊灬啊灬啊灬好深灬快高潮了动漫-国产字幕国产在线观看-B049AV | 自怕偷自怕亚洲精品| 亚洲免费人妻在| 毛片17S| 日本精品一区二区三| av网站在线看| 亚洲操逼无码| 青青色综合| 日日97| 免费a级毛片av无码久久精品中文字幕| 欧美激情中文字幕另类小说| 少妇99成人麻豆| 啊啊啊啊啊舒服| av毛片aaaaa免费看| 人人考人人摸人人干| 亚洲强奸乱伦影视网| 亚洲无码99| 蜜桃狠狠色伊人亚洲综合 | 国产精品人妻无码久久久老鸭窝 | 9997se| 日本一区二区三区免费观看| 亚洲国产一区二区三区四区国产| 天堂国产AV| 家庭乱伦国产精品| 性爱动态120秒| 欧美78P| 天天干天天做| 久久精品无码熟妇一区二区三区视频导航 | 亚洲天天操| 日韩有码一区三区| 欧美一区二区三区入口| 天天影视色香色欲| 日本性感人妻91| 国产精品探花视频| 欧美超碰9798| 美女被啪到深处抽搐视频| 开心五月婷婷| 熟女探花啪啪| 欧美情色贴图| 色天使亚洲综合在线观看| 久操在97| 美女自卫慰黄网站免费| 97天天| 婷婷久草一区二区三区| 国产精品白领在线观看 | 国产 日韩 欧美 中文 另类,国产 欧美 另类 制服 变态,高清 日韩 欧美 中文,高 | 人妻81p| 啊啊啊啊啊啊啊啊要喷了| 韩国三级理论在线| 亚洲欧美色图片| 少妇色综合| 天天干,夜夜爽| A级毛片在线看免费| 大屁股熟女一区二区三区| 天美精品av| 无码精品人妻一区二区三区妖精| 4tube欧美女厕所| 亚洲伊人久久精品狠狠在线| 亚洲综合中文字幕有码| 中文字幕国产在线天堂| 国产精品大屁股999| 中文字幕一区二区三区人妻少妇在线 | 婷婷五月天补不补| 操逼免费视频无码国产| 色综合91好| 自拍第一页| 欧美老妇女内射网址| 91美女丝袜诱惑视频| 盗摄女人妻在线| 正在播放国产精品一区| 97碰碰色| 秘书高跟黑色丝袜国产91在线| 日本999精品视频| 日韩美女久久一区二区三区| 亚洲乱码国产乱码精网站| 18禁止看精品中文字幕| 精品女同一区二区三区| 精彩久久中文| 日韩中文字幕av在线播放| 啊啊啊啊一区| 色五月激情网| 综合色图区| 色综合美国| 欧美极品女人的天堂| 五月婷丁香| 成人情色一区二区| 丁香五月激情网| 在线观看十八禁| 福利偷拍视频-中文字幕2019国语完整视频大全-S91AV | 日韩欧美蜜桃精品久久中文字幕久久| 动漫片子网站3黄| 久久久久七视频| 欧美日韩另类在线| 蜜乳成人AV| 亚洲五码一区二区三区| 亚洲制服欧美另类内射| 五月天精品| 亚洲综合性感在线| 欧美日韩亚洲电影| 97精品全部| 亚洲密乳AV| 偷窥自拍A片| 国产精品久久9| 无卡一区=区| 思思久热在线精品66| 国产一在线观看| 人妻嗯啊啊在线播放| 欧美性爱一内片一区二区三区| 亚洲drav色图| 另类图片综合| 4399成人黄A片| 欧美91精彩| 欧亚日韩一区在线| 爆操无码| 国模不卡一本二本三电影| 九九热精品视频六| 脫衣舞一区二区三区| 成人夜夜爽| 欧美草草高清日韩视频| 欧美性爱18观看| http://qxhbdz.com| 国产精品夜夜夜| 国产精品毛片?v一区二区三区| 精品一区二区三区蜜桃臀赵总 | 大香交| 手机在线视频国内精品| 日本熟人妻中文字幕在线|...久久国产精品-国产精品_日本一区二区三区中文字幕 | 啊视频在线| 天天干夜夜| 日本精品国产视频| 亚洲成a人v欧美综合天堂下载| 日韩欧美亚洲一区二区三区影院| 美女诱惑在线一区| .精品人妻一区二区三| 四虎国产精品永久入口| 男女啊啊啊啊啊| 性做久久久久久免费观看软件| 国产中文福利| 欧美亚洲色图另类国产| 九九夜精品九九在线| 国产对白刺激视频| 青草视频人妻在线观看| 日韩精品中文字幕一| 国产一区二区在线播放,久久亚洲精品中文字幕第一区,亚洲精品在线中文字幕视频 | 五月丁香激情啪啪| 少妇淫妇久久久久久久| 天天影视色香色欲| 好色综合| 久热久| 97久久超碰| 国产精品内射婷婷一级二| 精品久久99| 欧美不卡二区| 久久日韩肥臀| 日本免费不卡二区| 国产又大又硬又长又粗| 91亚洲电影| www.高清无码诱惑一区.com | 黄色交缠性感爆操91国产精品免费一区二区三区 | 国产夜夜操| 国产乱码精品一区二区三区四川| 国产日韩美女小穴视频网站不卡| 人妻熟女一区在| 岛国视频免费在线观看| 色欲av国内精品久久久久久| 97色诱| 玖色AV| 国产九九九九九九九九| 亚洲 小说 欧美 激情 另类| 精品女同一区| 人妻爽爽啪视频| 免费视频在线观看啊啊啊啊啊| 日本在线视频导航| 草莓精品视频在线免费观看| 啊啊啊操死我| 久久在肏| chaopen97久久| 国产精品色约约| 伦在线97| 啊啊啊啊在线观看网址| 嗯嗯啊啊啊好舒服| 天天透伊人| 色999人与兽|