亚洲有码Av一区二区三区_国产高清啪啪免费视频_69色视频国产_国产成人人人爆出白浆_国产精品自在线拍国_一本久久伊人热热精品无码_午夜性刺激在线看免费带字幕_助力高品质欧美狂喷水_亚洲精品日韩无码_精品无码一区二区三区蜜臀_麻豆高清国产AV_熟妇人素无码中文字幕_亚洲a级片在线观看_国产欧美日韩三区_99国产成人高清在线观看

ARTICLE DETAIL

資訊詳情

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

前綴樹解決表達(dá)式樹緩存難題:從字典到結(jié)構(gòu)匹配的優(yōu)化實踐

前綴樹解決表達(dá)式樹緩存難題:從字典到結(jié)構(gòu)匹配的優(yōu)化實踐 前一段時間我在推進(jìn)一個動態(tài)查詢服務(wù)業(yè)務(wù)方把篩選條件直接以結(jié)構(gòu)化的方式傳給后端后端要把這些條件拼成表達(dá)式樹再編譯成委托塞給數(shù)據(jù)訪問層。量小的時候一切正常等壓測一上來CPU 直接被打到 80% 以上——不是查詢慢而是卡在表達(dá)式樹的構(gòu)建和 Compile 上。那一刻我才真正意識到兩件事第一表達(dá)式樹的構(gòu)建和編譯成本比想象中高得多第二對這個東西做緩存并沒有一開始想的“放個字典”那么簡單。后來我換了個思路把緩存結(jié)構(gòu)從前綴樹的角度重新做了一版效果非常明顯。這篇內(nèi)容就是把我完整的思考過程、踩過的坑、落地的代碼細(xì)節(jié)都整理出來。如果你也在做動態(tài) LINQ、對象映射器、規(guī)則引擎、或者任何需要頻繁構(gòu)造和編譯表達(dá)式樹的服務(wù)這篇文章大概率能幫你省下不少 CPU。1. 表達(dá)式樹緩存為什么沒有想象中簡單1.1 表達(dá)式樹不是普通對象沒法直接當(dāng)字典鍵很多人第一反應(yīng)是緩存嘛搞一個Dictionaryobject, T不就行了。表達(dá)式樹本身是對象直接用實例做 key 不行嗎不行。表達(dá)式樹內(nèi)部是一堆對象引用互相連接根節(jié)點是一個 LambdaExpression下面掛 BodyBody 里又有 Left、Right、Arguments 之類的子節(jié)點。最關(guān)鍵的問題是兩個邏輯上完全等價的表達(dá)式例如ExpressionFuncUser, bool expr1 u u.Age 18; ExpressionFuncUser, bool expr2 v v.Age 18;它們在運行時創(chuàng)建出來完全不同的對象圖。expr1和expr2的引用不相等內(nèi)部的 MemberExpression、ParameterExpression、ConstantExpression 也全部是獨立實例。你用ReferenceEqualityComparer做 key同一個邏輯的表達(dá)式也會被當(dāng)成不同條目緩存命中等于零。有人可能會說那我把表達(dá)式樹轉(zhuǎn)成字符串存字典不就好了。這個方向是對的但里面藏著很多坑下面單獨說。1.2 字符串 Key 方案的三個硬傷字符串方案是網(wǎng)上最常見的做法核心思路就是expr.ToString()或者序列化成某種文本形式然后用這個字符串當(dāng) key。我在第一版也是這么干的跑了一段時間后發(fā)現(xiàn)三個硬傷。第一個硬傷是ToString()的輸出不穩(wěn)定。表達(dá)式樹的ToString生成的字符串在不同運行環(huán)境下并不是完全等價的。比如常量decimal或double的格式化可能受當(dāng)前 Culture 影響一元表達(dá)式可能會因為括號層級不同產(chǎn)生不一樣的輸出形式甚至有些自定義表達(dá)式節(jié)點的ToString行為完全不可控。一旦 key 不穩(wěn)定同一個表達(dá)式在某個線程下生成 key A在另一個線程下生成 key B緩存就形同虛設(shè)。第二個硬傷是字符串生成本身的代價。expr.ToString()是一次完整的樹遍歷每次請求都先遍歷整棵樹生成字符串再用字符串去字典里查找。這等于把“構(gòu)建表達(dá)式樹”的解析成本省了但遍歷成本和字符串分配成本全留下了。表達(dá)式一復(fù)雜字符串長度輕松上千字符字符串比較又得逐字符比對算下來并沒有比重新 Compile 快太多。第三個硬傷是字符串 key 的內(nèi)存浪費。一個表達(dá)式轉(zhuǎn)成字符串動不動幾百上千字符如果業(yè)務(wù)請求有幾千上萬個變體光 key 就吃掉不少內(nèi)存。而且字符串 key 和表達(dá)式樹的內(nèi)部結(jié)構(gòu)完全是兩種維度如果你后續(xù)想調(diào)整匹配規(guī)則比如忽略參數(shù)名、忽略某些子表達(dá)式用字符串做 key 會非常痛苦因為你還得先做字符串解析和正則替換。1.3 緩存命中之后還要考慮編譯階段還有一個很容易被忽略的點緩存的目標(biāo)到底是什么。如果只緩存“表達(dá)式樹對象”命中了確實省掉了重新Expression.XXX()一堆方法調(diào)用的時間但表達(dá)式樹被使用的時候往往還要Compile()成委托。Compile()階段涉及 IL 生成、類型元數(shù)據(jù)讀取、委托構(gòu)造這部分成本在大多數(shù)場景下比“構(gòu)建表達(dá)式樹”還高尤其是需要反射訪問復(fù)雜成員或調(diào)用鏈很長的時候。所以我在設(shè)計緩存的時候目標(biāo)從一開始就不是“緩存表達(dá)式樹”。而是直接把“同一個結(jié)構(gòu)的表達(dá)式”對應(yīng)的已編譯委托緩存下來。這樣命中后連Compile()都省了。而表達(dá)式樹對象本身只是當(dāng) key 的匹配依據(jù)。這個目標(biāo)設(shè)定決定了后面整個數(shù)據(jù)結(jié)構(gòu)的選擇。2. 前綴樹憑什么適合承載表達(dá)式樹緩存2.1 前綴樹的一層對應(yīng)表達(dá)式樹的一層前綴樹也叫 Trie本質(zhì)上是一種多叉樹。它的特點是根節(jié)點不存數(shù)據(jù)樹的每一層對應(yīng)判定序列中的一環(huán)從根到葉子的路徑拼起來就是完整的判定序列。和普通字典相比它的最大優(yōu)勢是能自動共享前綴。那這件事和表達(dá)式樹有什么關(guān)系關(guān)系很大因為表達(dá)式樹本身就是一棵樹。兩棵表達(dá)式樹如果結(jié)構(gòu)相似它們的前半段路徑大概率是重疊的。比如u u.Age 18 v v.Age 18這兩棵樹從根節(jié)點的 Lambda 開始參數(shù)類型相同Body 是一個二元比較節(jié)點二元節(jié)點的 NodeType 都是 GreaterThan左子節(jié)點都是訪問 User 的 Age 屬性右子節(jié)點都是常量 18。如果用“節(jié)點的類型和特征”組成判定序列那么這兩棵樹的判定序列從頭到尾完全一致自然會在前綴樹中走到同一條路徑最終命中同一個緩存項。這就是前綴樹相比字典的底層優(yōu)勢字典的 key 是整體匹配前綴樹的匹配是逐層進(jìn)行的結(jié)構(gòu)越相似匹配過程中越早匯合天然支持結(jié)構(gòu)共享。2.2 維度序列把樹壓平成逐層判定要使用前綴樹首先得把一棵“樹”變成一個“序列”。這個序列不是簡單地把所有節(jié)點平鋪而是要保證父節(jié)點的判定特征在序列中一定出現(xiàn)在子節(jié)點之前。這樣前綴樹的每一層對應(yīng)表達(dá)式樹中的某一層從根開始逐層對齊。我做了一個叫“維度序列”的東西。樹的每個節(jié)點轉(zhuǎn)化成一條邊Edge一條邊包含三個字段節(jié)點的表達(dá)式類型NodeType比如GreaterThan、MemberAccess、Constant、Parameter。子節(jié)點數(shù)量ChildCount用來區(qū)分同一類型但子結(jié)構(gòu)不同的情況。輔助哈希AuxHash用來細(xì)化特征比如成員訪問的成員名、方法調(diào)用的方法簽名、參數(shù)的類型、常量值的類型和值哈希。舉個具體例子表達(dá)式u u.Age 18的維度序列大致是Lambda(參數(shù)類型: User, 參數(shù)個數(shù): 1) - GreaterThan(子節(jié)點: 2) - MemberAccess(User.Age, 子節(jié)點: 1) - Parameter(User) - Constant(int, 18)注意我在這里把 Lambda 的參數(shù)類型和數(shù)量也放進(jìn)了序列。這一點很重要因為兩個表達(dá)式即使 Body 完全一樣如果參數(shù)類型不同語義也不同必須區(qū)分開。后續(xù)每一步都沿著先序順序繼續(xù)展開直到葉子節(jié)點。把這個序列放進(jìn)前綴樹里等于給每個表達(dá)式建立一條路徑。查找時只需要拿著同樣方式生成的維度序列從前綴樹根節(jié)點開始逐層往下走即可。2.3 對照前綴樹 vs 字典 vs 表達(dá)式比較器這里我簡單做一個方案對比方便大家看清為什么最終選了前綴樹。方案命中粒度查詢復(fù)雜度實現(xiàn)成本典型問題字符串作為 key整體匹配O(字符串長度)低ToString 不穩(wěn)定、字符串分配大、無法忽略參數(shù)名引用相等做 key只有同一個實例命中O(1)極低等價表達(dá)式無法命中形同虛設(shè)規(guī)范化后比較結(jié)構(gòu)等價命中O(樹規(guī)模)高每次比較都遍歷全樹沒有共享前綴樹前綴共享O(序列深度)中需要處理規(guī)范化、分支膨脹但查找非??爝@里的“規(guī)范化后比較”是指用微軟的表達(dá)式比較器一類工具把每個節(jié)點逐個比對。如果緩存里存了 1 萬條表達(dá)式來一個新表達(dá)式要依次比對 1 萬次每次都是一次完整樹遍歷。前綴樹則是直接按維度序列尋徑查一次樹的深度也就是表達(dá)式樹的深度完全不管緩存里有多少條這是數(shù)量級上的差異。3. 落地實現(xiàn)節(jié)點設(shè)計、歸一化與增刪查3.1 邊結(jié)構(gòu) TrieEdge 與節(jié)點結(jié)構(gòu)先定義邊。邊就是我在 2.2 里說的維度序列中的一個元素。這里我用一個只讀結(jié)構(gòu)體public readonly struct TrieEdge : IEquatableTrieEdge { public ExpressionType NodeType { get; } public int ChildCount { get; } public int AuxHash { get; } public TrieEdge(ExpressionType nodeType, int childCount, int auxHash) { NodeType nodeType; ChildCount childCount; AuxHash auxHash; } public bool Equals(TrieEdge other) { return NodeType other.NodeType ChildCount other.ChildCount AuxHash other.AuxHash; } public override int GetHashCode() { unchecked { var hash (int)NodeType; hash (hash * 397) ^ ChildCount; hash (hash * 397) ^ AuxHash; return hash; } } }AuxHash 具體怎么算邏輯不一樣。拿成員訪問舉例訪問User.Age輔助哈希就是nameof(Age)和聲明類型typeof(User)的組合哈希如果是方法調(diào)用就是方法名、聲明類型、方法簽名的組合哈希如果是常量節(jié)點就是常量值的類型哈希加上值本身的哈希??傊o助哈希的目的是區(qū)分“同類型、同子節(jié)點個數(shù)但語義不同”的節(jié)點。接下來是前綴樹節(jié)點public class ExpressionTrieNode { private readonly DictionaryTrieEdge, ExpressionTrieNode _children new(); public bool HasCachedValue { get; private set; } public LambdaExpression CachedExpression { get; private set; } public Delegate CachedDelegate { get; private set; } public bool TryGetValue(out Delegate compiledDelegate) { compiledDelegate null; if (!HasCachedValue) return false; compiledDelegate CachedDelegate; return true; } public void SetValue(LambdaExpression expression, Delegate compiledDelegate) { HasCachedValue true; CachedExpression expression; CachedDelegate compiledDelegate; } public ExpressionTrieNode GetOrAddNode(TrieEdge edge) { if (_children.TryGetValue(edge, out var existing)) return existing; var newNode new ExpressionTrieNode(); _children.Add(edge, newNode); return newNode; } public bool TryGetNode(TrieEdge edge, out ExpressionTrieNode node) { return _children.TryGetValue(edge, out node); } }這個節(jié)點的結(jié)構(gòu)很簡單每個節(jié)點存三個東西子節(jié)點字典、是否已有緩存值、緩存下來的表達(dá)式和編譯委托。3.2 參數(shù)重命名與閉包展開這部分是整個方案真正的核心也是我踩坑最多的地方。如果直接拿原始表達(dá)式樹生成維度序列那么u u.Age 18和v v.Age 18會被判定為兩條完全不同的路徑因為公共語言運行時會認(rèn)為u和v是兩個不同的 ParameterExpression 實例。所以必須先做“參數(shù)歸一化”。我實現(xiàn)了一個參數(shù)重寫器本質(zhì)是把 Lambda 里出現(xiàn)的所有參數(shù)按“第一次出現(xiàn)順序”統(tǒng)一改名為p0、p1這樣的占位符之后再插入前綴樹。這樣兩個邏輯等價但參數(shù)名不同的表達(dá)式生成的維度序列就完全一致了。public class ParameterNormalizer : ExpressionVisitor { private readonly DictionaryParameterExpression, ParameterExpression _map new(); protected override Expression VisitParameter(ParameterExpression node) { if (!_map.TryGetValue(node, out var normalized)) { normalized Expression.Parameter(node.Type, $p{_map.Count}); _map[node] normalized; } return normalized; } protected override Expression VisitLambdaT(ExpressionT node) { var body Visit(node.Body); var parameters node.Parameters.Select(p (ParameterExpression)VisitParameter(p)).ToArray(); return Expression.Lambda(body, parameters); } }注意VisitLambda里必須先重寫參數(shù)節(jié)點本身再重寫 Body。而且同一個 ParameterExpression 實例可能在 Body 中出現(xiàn)多次VisitParameter里的字典會保證同一個實例始終映射到同一個歸一化參數(shù)。另一件必須處理的事情是閉包展開。動態(tài)查詢里經(jīng)常會寫int minAge GetMinAgeFromConfig(); ExpressionFuncUser, bool expr u u.Age minAge;minAge會被編譯器捕獲成閉包然后在表達(dá)式樹里體現(xiàn)為一個ConstantExpression這個常量的值是一個編譯器生成的閉包對象。問題是每次調(diào)用GetMinAgeFromConfig()閉包對象都是新的哪怕minAge的值一模一樣表達(dá)式樹的常量節(jié)點引用也不一致緩存照樣不命中。解決辦法是在參數(shù)歸一化之前先把閉包里的字段“攤開”成真正的常量值。我用一個自定義的表達(dá)式訪問器public class CaptureExpander : ExpressionVisitor { protected override Expression VisitMember(MemberExpression node) { if (node.Expression is ConstantExpression constant) { var declaringType node.Member.DeclaringType; if (declaringType ! null declaringType.IsDefined(typeof(CompilerGeneratedAttribute), false)) { object value node.Member switch { FieldInfo field field.GetValue(constant.Value), PropertyInfo property property.GetValue(constant.Value), _ null }; if (value ! null (value.GetType().IsPrimitive || value is string || value is decimal || value is DateTime || value is Guid)) { return Expression.Constant(value, node.Type); } } } return base.VisitMember(node); } }這段代碼的作用是如果發(fā)現(xiàn)成員訪問的“源”是一個編譯器生成閉包就反射讀取字段的值。如果是基礎(chǔ)類型直接替換成常量節(jié)點。這樣u.Age minAge就變成了u.Age 3030 這個值直接參與哈希計算閉包對象的版本差異就被消除掉了。這里有個邊界必須小心如果閉包字段的值是引用類型而且后面還繼續(xù)訪問它的子成員一層展開就可能不夠。比如u u.Address.City Shanghaiu.Address是 User 對象的成員不涉及閉包沒問題但string prefix ...; u u.Name.StartsWith(prefix)里面的 prefix 是閉包字段展開成常量后可以直接匹配。對于SomeConfig config ...; u u.Age config.MinAge閉包展開只做一層的話會把config展開成Constant(config 實例引用)那這個實例引用每次可能還是不同。這種情況我目前的處理方法是如果第一層展開后仍然是個比較復(fù)雜對象的實例就遞歸往下展開字段直到遇到基礎(chǔ)類型如果遞歸層數(shù)太深就直接放棄緩存該表達(dá)式走原來的編譯邏輯。這個策略對大多數(shù)業(yè)務(wù)場景已經(jīng)夠用。3.3 插入和查找的完整過程把表達(dá)式“洗”干凈之后剩下的就是生成維度序列并插入前綴樹。我用一個遞歸函數(shù)按先序順序把整棵表達(dá)式樹壓平為一條邊序列private static void AppendEdges(Expression node, ListTrieEdge edges) { switch (node) { case LambdaExpression lambda: { var hash 17; foreach (var p in lambda.Parameters) hash HashCode.Combine(hash, p.Type); edges.Add(new TrieEdge(ExpressionType.Lambda, lambda.Parameters.Count 1, hash)); AppendEdges(lambda.Body, edges); break; } case BinaryExpression binary: edges.Add(new TrieEdge(binary.NodeType, 2, 0)); AppendEdges(binary.Left, edges); AppendEdges(binary.Right, edges); break; case UnaryExpression unary: edges.Add(new TrieEdge(unary.NodeType, 1, 0)); AppendEdges(unary.Operand, edges); break; case MemberExpression member: { int childCount member.Expression null ? 0 : 1; var hash HashCode.Combine(member.Member.Name, member.Member.DeclaringType); edges.Add(new TrieEdge(ExpressionType.MemberAccess, childCount, hash)); if (member.Expression ! null) AppendEdges(member.Expression, edges); break; } case MethodCallExpression call: { int childCount (call.Object null ? 0 : 1) call.Arguments.Count; var hash HashCode.Combine(call.Method.Name, call.Method.DeclaringType, call.Method.GetParameters().Length); edges.Add(new TrieEdge(ExpressionType.Call, childCount, hash)); if (call.Object ! null) AppendEdges(call.Object, edges); foreach (var arg in call.Arguments) AppendEdges(arg, edges); break; } case ConstantExpression constant: { int valueHash GetValueHash(constant.Value); int hash HashCode.Combine(constant.Type, valueHash); edges.Add(new TrieEdge(ExpressionType.Constant, 0, hash)); break; } case ParameterExpression parameter: edges.Add(new TrieEdge(ExpressionType.Parameter, 0, parameter.Type.GetHashCode())); break; default: // 其他不常見節(jié)點類型直接按類型哈希走 edges.Add(new TrieEdge(node.NodeType, 0, node.Type.GetHashCode())); break; } }GetValueHash對于值類型直接調(diào)GetHashCode()對于字符串也直接用字符串哈希對于其他對象則退回到引用哈希防止把一個大對象序列化進(jìn)來導(dǎo)致性能劣化。有了邊序列之后插入和查找就非常簡單了。插入是從根節(jié)點開始按邊序列挨個走走到哪沒有子節(jié)點就創(chuàng)建一個直到序列結(jié)束然后在終點節(jié)點塞入表達(dá)式和編譯委托。查找則完全一樣地走如果中途任一層找不到對應(yīng)邊直接返回未命中。這里我把提交編譯委托和查找合并成一個方法public Delegate GetOrCompileTDelegate( ExpressionTDelegate seed, FuncExpressionTDelegate, Delegate compiler) where TDelegate : Delegate { // 1. 閉包展開 var expanded new CaptureExpander().Visit(seed); // 2. 參數(shù)歸一化 var normalized new ParameterNormalizer().Visit(expanded); // 3. 生成邊序列 var edges new ListTrieEdge(); AppendEdges(normalized, edges); // 4. 前綴樹查找/插入 ExpressionTrieNode current _root; foreach (var edge in edges) { if (!current.TryGetNode(edge, out var next)) { lock (current) { next current.GetOrAddNode(edge); } } current next; } if (current.TryGetValue(out var cachedDelegate)) return cachedDelegate; var compiled compiler(normalized as ExpressionTDelegate); current.SetValue(normalized as LambdaExpression, compiled); return compiled; }實際項目中compiler參數(shù)不需要由調(diào)用方傳內(nèi)部直接調(diào)expression.Compile()就行。我這里留成一個委托參數(shù)是為了方便測試時替換各位可以直接寫成Compile()。3.4 并發(fā)讀寫的一個可落地方案前綴樹和普通字典不一樣它不能靠一個簡單的 ConcurrentDictionary 就解決并發(fā)問題因為一次插入要沿著路徑創(chuàng)建多個節(jié)點。如果兩個線程同時插入同一個前綴路徑很容易在中間節(jié)點上產(chǎn)生競爭。我用的方案是GetOrAddNode這一步在鎖內(nèi)做雙重檢查。上面代碼里已經(jīng)體現(xiàn)了if (!current.TryGetNode(edge, out var next)) { lock (current) { next current.GetOrAddNode(edge); } }這里 lock 的對象就是當(dāng)前節(jié)點。因為TrieEdge是只讀結(jié)構(gòu)體節(jié)點的子節(jié)點字典只在插入時修改查找時只讀。兩個線程同時走到同一節(jié)點時都嘗試在它的_children里加同一條邊但加鎖保證了只有一個線程真正創(chuàng)建新節(jié)點另一個線程走完鎖之后發(fā)現(xiàn)已經(jīng)有了直接復(fù)用。對于讀多寫少的服務(wù)里這個鎖競爭幾乎可以忽略不計。因為它只在“第一次遇到某個邊”時才觸發(fā)后續(xù)所有請求都是純字典讀取不碰任何鎖。如果你追求極端并發(fā)性能可以在每個節(jié)點上用一個ReaderWriterLockSlim但就我的實測來看雙重檢查鎖已經(jīng)足夠。還有一點值得注意如果某個分支走完整個序列后發(fā)現(xiàn)沒有緩存值并發(fā)插入還沒完成可能會產(chǎn)生重復(fù)編譯。我目前的策略是拿到終點節(jié)點后先看有沒有值沒有就編譯編譯結(jié)束后再SetValue。在多線程下可能出現(xiàn)同一路徑被編譯多次的情況但因為后續(xù)線程都能復(fù)用第一次寫入的值所以最多只會多編譯幾次不會造成正確性問題。如果你接受不了這點可以在終點節(jié)點上加一個LazyDelegate做單次初始化效果更好。4. 實測效果、邊界情況與兩個重要提醒4.1 三套方案的對比數(shù)據(jù)為了驗證這套方案到底值不值得做我寫了一個模擬測試生成了 10 萬條結(jié)構(gòu)不同但有一定重合度的動態(tài)表達(dá)式所有表達(dá)式都是User類型上的謂詞組合包含屬性訪問、常量比較、字符串匹配、閉包捕獲然后分別用無緩存、字符串字典緩存、前綴樹緩存跑了一遍。需要說明的是這個測試是為了橫向比較方案之間的相對差異不是造數(shù)據(jù)吹一個絕對數(shù)字。不同機器、不同表達(dá)式復(fù)雜度一定會導(dǎo)致絕對值變化但相對關(guān)系是穩(wěn)定的。方案平均單次總耗時命中率內(nèi)存占用趨勢無緩存每次構(gòu)建加編譯約 1.2ms0每次請求都會產(chǎn)生新對象GC 壓力最大字符串 key 字典緩存約 0.35ms能命中但受 ToString 穩(wěn)定性影響字符串 key 和表達(dá)式樹都存著中等前綴樹緩存委托約 0.08ms結(jié)構(gòu)等價即可命中含參數(shù)名無關(guān)匹配節(jié)點多分支多內(nèi)存偏高但可控最直觀的感受是前綴樹方案比字符串方案快了 4 倍左右和完全無緩存比快了 15 倍。字符串方案最大的開銷其實不在字典查找而是在每次請求生成ToString()的字符串和后續(xù)字符串哈希。前綴樹方案省掉這一步而且查詢是逐結(jié)構(gòu)走路徑走完基本就到底了幾乎沒什么額外計算。4.2 常量對象引用導(dǎo)致的假不命中前綴樹方案有一個非常大的坑第一次跑測試時我花了好長時間才定位出來常量節(jié)點的哈希不能用對象引用否則緩存命中率會斷崖式下跌。舉個例子用戶查詢City Shanghai每次生成的ConstantExpression都是一個新的string對象。雖然字符串的GetHashCode()是按內(nèi)容算的所以對于字符串還好。但如果常量是某一個自定義配置對象比如ExpressionFuncUser, bool expr u u.Category currentCategory;其中currentCategory是一個Category對象每次請求從數(shù)據(jù)庫加載出來都是新實例。如果哈希直接currentCategory.GetHashCode()那引用變了哈希就變緩存必然不命中。我的解決辦法是在GetValueHash里做一個分支判斷只有值類型、字符串、decimal、DateTime、Guid 這類“語義值”參與哈希計算其他對象一律退回“類型哈?!倍皇菍ο蠊?。這樣即使閉包對象每次都是新實例只要類型相同常量節(jié)點就被認(rèn)為是同一個維度上的后續(xù)閉包展開已經(jīng)把真實值替換成基礎(chǔ)類型所以這個退化策略不會造成語義錯誤。如果業(yè)務(wù)里確實需要緩存“復(fù)雜對象常量值”不同的表達(dá)式那就要給這個對象的 “Equals” 和GetHashCode做好值語義或者把它序列化成穩(wěn)定字符串再參與哈希。否則就老實讓緩存失效不要為了追求命中率引入錯誤風(fēng)險。4.3 分支膨脹與定期裁剪前綴樹也有自己的代價它把大量公共前綴拆成了很多細(xì)粒度節(jié)點每一條沒命中過的分支都會在樹里留下永久節(jié)點。如果業(yè)務(wù)表達(dá)式變化非常零散緩存分支可能會不成比例地膨脹。我第一次上線時沒處理這個問題運行了一周后看內(nèi)存發(fā)現(xiàn)前綴樹占用的內(nèi)存比所有緩存表達(dá)式委托加起來還要多。原因是很多請求是“一次性變體”某個表達(dá)式只出現(xiàn)過一兩次但它在樹上留下了一條完整路徑這條路徑永遠(yuǎn)不會再被訪問。后來我加了一個輕量級計數(shù)器每個節(jié)點記錄最后一次訪問的時間戳和命中次數(shù)。定時任務(wù)每小時掃描一次把所有葉子節(jié)點那一側(cè)、訪問次數(shù)為零、且超過一段時間未訪問的分支剪掉。注意裁剪一定要從葉子往上剪不能從中間切否則會把有緩存值的根路徑誤刪。對于大多數(shù)業(yè)務(wù)其實可以先不加裁剪功能但要心里有數(shù)如果緩存條目的規(guī)模在千萬級以上內(nèi)存控制就會變成主要矛盾。4.4 跨進(jìn)程一致性提醒還有一個容易踩的坑字符串和哈希值在不同的 .NET 運行時版本之間不具備跨進(jìn)程一致性。string.GetHashCode()在 .NET Core 3.0 之后開始引入進(jìn)程內(nèi)隨機化同一個字符串在不同進(jìn)程里算出來的哈希很可能不一樣。PropertyInfo.GetHashCode()也類似它和反射對象的元數(shù)據(jù)身份綁定不同進(jìn)程加載同一個類型時返回的哈希不一定相同。所以這種前綴樹緩存只能用在進(jìn)程內(nèi)緩存場景千萬不要把輔助哈希值算好后塞進(jìn) Redis 或者其他分布式緩存里再拿去跨進(jìn)程匹配。如果你真要做分布式表達(dá)式緩存那就得先定義一套完全確定性的規(guī)范化序列化協(xié)議把這個協(xié)議作為 key前綴樹只負(fù)責(zé)進(jìn)程內(nèi)的快速匹配。序列化的成本會吃掉一部分性能優(yōu)勢所以我的建議是如果分布式是硬需求進(jìn)程內(nèi)只緩存編譯委托分布式只緩存表達(dá)式樹的內(nèi)容別混著用。5. 我的實踐體會與后續(xù)擴(kuò)展這套方案我從最初用字符串字典踩坑到后來改成前綴樹最大的感受是表達(dá)式樹這種結(jié)構(gòu)用線性容器去承載是天然不舒服的它本身就是樹讓緩存結(jié)構(gòu)也貼近樹的形態(tài)才是順理成章的事。在這個實現(xiàn)里我每次比對一個節(jié)點都不會遞歸整棵子樹而是走一條路徑這條路徑的長度最多就是表達(dá)式樹的深度。這也是為什么在表達(dá)式數(shù)量的規(guī)模變大之后前綴樹方案的性能曲線依然很平坦而字典方案早就開始肉眼可見地變慢了。如果以后要繼續(xù)往下做我可能的擴(kuò)展方向有這么幾個一是把邊序列生成器從硬編碼的 switch 改成基于表達(dá)式訪問器的可擴(kuò)展管線方便接入自定義表達(dá)式節(jié)點二是把節(jié)點內(nèi)的子節(jié)點字典在某些高熱點分支上替換成固定數(shù)組用索引訪問代替字典哈希進(jìn)一步降低單次查找的常數(shù)因子三是把閉包展開邏輯做更深層的遞歸配合類型緩存把任意深度的閉包字段自動替換成值常量這樣動態(tài)查詢的緩存命中率還能再往上走一截。最后說一個很多人會忽略的小技巧處理表達(dá)式樹之前先調(diào)用一次Expression.CanReduce看看節(jié)點能不能歸約。不少從語法樹轉(zhuǎn)換過來的表達(dá)式會帶有冗余的轉(zhuǎn)換節(jié)點如Convert不提前歸約的話同樣邏輯的表達(dá)式會因為是否帶轉(zhuǎn)換節(jié)點而產(chǎn)生兩種維度序列緩存命中率和分支膨脹都會受影響提前歸約一次能省很多不必要的麻煩。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
9.1小视频| 久久精品一区二区三区不卡| 久久线上视频免费看| 久久一二三四五六七八九区区区 | 强奸乱伦AV网站| 日韩无码第3页| 亚洲欧美另类少妇精品| 操91| 激情婷婷综合久久| 99热99re6国产在线播放| 成人AV素股で擦久久| 97在线精品观看视频| 精品久操| 欧美白嫩女HD| 青青草国产亚洲精品久久| 夜间福利片1000无码| 极品人妻少妇综合| 日日做夜狠狠爱欧美黑人| 亚洲精品三| 亚州情色j区| 五十路三区在线| 国产白嫩精品久久| 久久精品国产精品亚洲艾通辽熟妇 | 中日992视频| 国产伦精品免编号公布| 天天综合网站| 国产精品午夜高潮呻吟久久av| 密臀在线一区尤物| 97超碰欧美手机在线| 中国黑人三级片网站上区| 激情综合五月| 亚洲五月天激情| 欧美亚洲第一页| 欧美精品三级黄片| 欧美巨大性舒爽顶到了| 老熟女91视频| 免费视频在线一区二区不卡| 黄色免费网| 九九九九国产| 欧美人妻少妇| 国产精品美女久久久久久网站| 欧美亚洲丝袜人妻制服中文99| 丝袜美女诱惑 91 视频| 亚洲男人的天堂网| 亚洲91大片| 夜夜高潮夜夜爽高清视频一| 中文字幕二区日韩天堂| 艹我哪美一区无码| 日本 欧美 亚中文字幕| 性爱久久| 一二三四免费视频| 亚洲欧洲精品成人| 啊啊啊啊啊好大好舒服想要| 亚洲一本色码中文字幕| 91AV天堂| 欧美色91| 91色插| 欧美 亚洲 第一页 | 超碰在线欧美性爱激情| 乱论91| 亚洲精品aa久久伊人| 秋霞影音一区二区三区| 日本99视频| 麻豆天美国美国产| 玖玖蜜臀资源网| 欧天美中出| 天天摸夜夜操视频| 亚洲图片 欧美电影| 亚洲色图一区二区三区| 亚洲国产精品成人久久蜜臀| 91白嫩| 黑人猛交| 男女激情黄色网址| 丁香九月激情| 精品然女一区二区| 国产91丝袜 在线播放| 五十路熟女人妻一区二区三区四区五| 国产精品视频91久久| 国产亚洲欧美每日在线| 三级三久久线久久99久目本WW| 亚洲色五月| 精品久久久久9999| 国产精品久久久久久久久久久久久久吹 | 欧美综合色,www| 亚洲色人阁| 免费av在线播放二区| 亚洲五码一区二区三区| 日日狠狠久久偷偷色综合免费| 五月天偷拍| 97免费免费视频网| 中文字幕97| 欧美97爱| 久久久久国产一区二| 久久天天摸| 色香伊人| 91人妻人人澡人人爽人人精品| 亚洲国产一区二区入口| 欧美v日韩欧亚洲电影天堂色诱,国产传媒| 性爱欧美五月| 久久永久无码人妻视频| 色综合色| 日韩欧美资源| 亚洲麻豆av一区二区| 操逼免费视频无码国产| 欧美后进式| 欧美 亚洲精品首页| 理论久久婷婷网 8| 麻豆色约约| 亚洲人体视频在线观看| 99免费在线视频| 亚洲图片在线| 黄色香蕉视频网站一区| 午夜天堂精品久久久久91| av操操不卡| 欧美丝袜亚洲| 亚洲激情在线| 国产suv精品一区| 人干人人人操人人摸| 97色97好| 26uuu国产亚洲综合| 九九亚洲视频| 国产AV天美传媒一区二区三区 | 搡老女人老妇女老妇老熟女怎么读| 偷拍在线观看视频| 久久久精品电影| 亚洲、日韩、综合、另类| 国产精品在线一区二区| 亚洲免费成人在线高清无码视频| 欧美嗯啊……在线观看视频免费| 九九亚洲| 少妇蜜汁| 亚洲久久久| 91GD.COM| 91狠狠综合网| 亚洲欧美校园另类春色| 午夜小电影在线插入淫高潮| 啊灬啊灬啊灬好深灬快高潮了动漫-国产字幕国产在线观看-B049AV | 精品射1999| 啪啪自拍九九综合| 夜夜爽33333| 一区二区视频在看| 成年男人的天堂| 亚洲人妻中文在线视频| 欧美 亚洲 另类 综合| 亚洲一区中文精品| 国产熟女二区| 思思在线免费视频| 亚洲熟女综合网| www.91色综合| 91成人高清在线观看| 五月天色电影| 日韩精品在线观看网站| 精品国产Av无码久久久伦古装| 欧美精品另类人妖xxxx| 中文操嬖片。| 内射夫妻三片| 美欧色综合| 看看小穴| 国产免费操逼| 97天天综合| 日韩人妻少妇中文字幕| 国产乱伦亚洲色图高清无码| 欧美人妖内射| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 欧美成人精品一区二区男人蜜臀| 男人的天堂在线有码| 少妇无码av专区线| 97综合在线| 加勒比五月天| 国产久久视频| 欧亚综合一卡二卡中文字幕| 熟女丝袜视频| 国产激情综合| 曰本人妻人人澡人人夹| 另类图片欧美激情综合| 亚洲天堂男人天堂网| 亚洲色图综合网| 精品人妻一区二区三区-国产| 大香蕉一线视频| 国产精品一区二区亚洲人成毛片| 亚洲图片小说欧洲| 国产熟女高潮一区二区三区| 成人A片男人的天堂| 亚洲五月婷婷| 黄色性爱网网| 搡老人老9丨女老熟人| 亚洲综合第一页| 熟女少妇一区二区三区| 久久噜噜噜精品国产亚洲综合| 天天综和| 97色欧州| 91亚洲影院综合| 人妻碰碰碰碰碰碰| 在线 亚洲 网爆 自拍| 91Chinese在线| 韩日性爱av| 日本色色视频网站| 成人小说视频在线精品欧美| www.色吧5.com| 色图综合网| 大香蕉99999| 国产精品白丝AV| 天天综合网合集91| 校园春色美腿丝袜| 欧美 亚洲 第一页| 亚洲男人天堂网| 亚洲综合电影| 天天摸夜夜添无码小视频| 老熟女乱伦一区| 91伊人久| 99久久婷婷丁香| 无码精品一区二区三区潘金莲| 91香蕉视频在线观看免费| 韩三级a视频在线观看| 免费AV中文网在线观看| 一个国产在线综合网站| 亚洲最大成人a毛毛片| 狠狠操夜夜| 人人摸人人摸人人干| 国产亚洲精品美女久久久m| 日韩乱中文| 99热只有这里有精品| 探花精品视频| 97精彩视频网站| 有码人妻系列| 精品美女久久一二三| 丝袜美腿射精91| 国产精品久久久午夜夜伦鲁鲁| 日韩91网| 97超碰人人模人人拍人人| 91色人妻| 亚洲精品 大香蕉| 91在线限制级| 91亚.色| 青青草好吊色| 人人操人人操草草| 丝袜美腿欧美| 天天舔天天日天天射| 青青青草伊人精品| 久久人妻| 欧美大香蕉专区网| 九九热免费国产视频婷婷伊人五月 | 香蕉av一区二区三区| 国内一级精品| 在线观看AV片| 澳门人妻久久| 熟女少妇一区二区三区| 国产日韩欧美操逼视频| 日韩AV片| 热热色AV| 最新岛国大片| 男人夜色天堂ss| 噜噜噜久久亚洲精品色情| 青青操日韩| 中文字幕在线免费观看2| 国产三级中文有码在线视频| 色噜噜人妻av 中文字幕| q2午夜理论片夜色av| 日本孕妇一区二区视频操逼免费看 | 熟女精品日韩一区二区三区 | 亚洲熟女乱色一区二区三区久久久| 黑人在线91| 69少妇一区二区| 天美传媒一二三区永久网站| yazhououmeizongya| 人人人摸人人| 日韩一级二级在线| 人人操欧美风骚| 你懂得91| 国产中文字幕在线观看| 啊啊啊啊啊在线视频| 人人妻人人色一区二区三区| 视频黄色国产一级| 欧美性爱网97| 人人操人人干网页| 白丝AV网站| 亚洲日韩天堂| 五月丁香在线| 蜜臀99久久精品久久久久久| 天堂中文资源在线bt| 中文字幕久久精视频久久大全| 伊人91| 天天爽爽爽爽| 女生久久网| 激情综合五| 青青草色AV| 色青青久久影视| 亚洲97网站| 国产精品久久久久久久黄无码| 97亚洲资源| 老外又粗又长一晚做五次| 97中文超碰| 91人人操| 蜜臀av中字字幕网站| 免费精品无码一级毛片牛牛影视| 久热69九色熟妇97| 日韩在线欧美精品一区二区| 久草资源在线视频官方总站日韩丝袜美腿| 国产色图乱伦| 91丝袜激情在线| 亚洲欧洲日韩天堂av| 超碰1024久久| 一区二区三区 日韩欧美| 国产精品毛片| 亚洲色图大香| 日本一区二区三区午夜观看| 风月影院男女十八禁| 激情久久久| 日韩无码人妻中字久久三区四区| 色五月婷婷网| 午夜小电影在线插入淫高潮| 国产美女91视频| 欧美一级黄片视频在线| 日日日日做夜夜夜夜做无码97| 日韩av不卡在线观看| 中文字幕午夜精品久久久| 国产精品成人在线| 先锋影音av先锋一区| 午夜后入| 久热这里| 俄罗斯一区二区视频在线观看| 日韩久草| 亚洲性爱高潮影院| 亚洲一欧洲中文字幕在线| 人妻熟女一区二区在线视频| 天天香香欲综合| 中文字幕交换人妻| 欧美激情专区| 视频在线97| 综合国产97| 久久久久久国产无码精品| 91超碰在线观看| 有码人妻系列| 五月天激情综合网| 狠狠色噜噜狠狠狠狠狠色综合久久 | 欧美一区二区三区大综合| 国产精品999zyz| 日日骚一区二区三区| 丰满人妻一区二区三区在线| 伊人婷婷五月天| 中文字幕精品免费一区二区| 91无码精品| 一区,二区,三区视频| 2018色综合天天操| 日本人人操人人操| 热久久国产| 91美女视频直播| 久插综合| 口爆欧美91| 91狠狠综合久久久| 黄片com.| 国产性爱在线视频一区二区| 精品国产Av无码久久久伦古装| 激情文学小说一区二区| 97公开久久| 91九久| 很很干很很操| 九九久久99| 一类av片在线看| 91性感在线| 日本道日本道中文字幕日本道最新日本道在线观看 | 日本熟妇浓毛hdsex| 97精品视频在线| 97超碰亚洲| 免费看美国人人爽,人人操| 欧美一级色| 一起草精品人妻| 黄色在线网站| 成人三一级一片aaa| 偷拍三区| 天天操人人操狠狠插| 91在线欧美| 久久久久女教师免费一区| 男女香蕉一区二区| 日本三级精品| 色欧洲| 欧美日韩狠狠爱| 91久久久久| 99久在线精品99re8| 天综合网欧美| 欧美日韩不卡传媒| 亚洲成人贴图| 91w欧美| 亚洲色图一区二区三区| 久久精品国产精品一区| 国内亚洲高清无码| 91精品久久久久五月天精品| 极品尤物自安慰| 久久久久久精品免费看A级| 嗯啊抽插大香蕉网页| 欧美日本中字另类在线| 日本视频在线观看污污污| 亚洲1区2区三区高清中文字幕| 尤物网址| 婷婷亚洲综合| 天天干美少妇一区| 成人女人国产| 欧美偷偷网| 伊人九九| 大香蕉乱级| 久久直播国产| 色色无码| 亚洲情色图片区| 五月天亚洲网| 日韩成人私密一级精品av| 秋霞一级鲁丝片A片| 中文字幕国产| 五月丁香六月| 乱码熟妇人妻久久久| 超碰欧美在线欧美| 国产精品网址| 密乳AV免费观看| 凹凸视频特色日本特黄| 亚洲s在线观看| 国产精品视频在线播放| 青青五月天| 天天日天天干天天色| 一级特级aaaa毛片免费观看| 日韩精品99999| 成人熟女区| 天天干人妻视频| 亚洲麻豆av一区二区| www.黄色在线| 亚洲精品天天影视综合网| 九九九草| 国产精品午夜福利亚洲综合网| 3D污黄视频在线观看| 97色插| 蜜臀久久99'精品久久久| 午夜αv| 中文字幕亚洲热播人妻| 天天噜| 26uuu欧美日韩| 亚州国产精品乱| 加勒比伊人综合| 国产白丝精品在线观看| 亚洲精品成人激情在线| 亚洲人妖网| 国产精品操| 久久精品色欧美aⅴ一区二区| 亚洲丝袜B诱惑| 欧美另类天堂| 亚洲色图殴美色图激情乱伦| 六月婷婷一区二区三区| 日韩国产精品人妻无码久久久| 操逼网免费无码视频| 欧美色图下一页| aa片毛片| 97国产色综合| 人人妻人人玩人人澡人人爽| 激情五月综合| 一区二区三区看视频| 91社区拍啪人妻| 热久久99999| 91精品国产91久久青草| 日韩AV一区二区三区四四| 亚洲欧美91√| 日本国产欧美高清在线| 国产女人9999| 欧日a| 台湾佬中文娱乐网久久久久久久久久com | 99福利社| 在线观看精品国产免费| 伊人亚洲综合| 夜夜天天噜狠狠爱2021| 成人精品视频| 日本精品一区二区中文字幕| 国产精品另类一区大香蕉| 夜色AV无码手机在线影院| 日韩精品9区| 综合天天网| 草莓精品视频在线免费观看| 精品少妇人妻| 最新国产精品久久精品| AV有码在线| 2020中文字幕| 久久永久无码人妻视频| 日本丝袜美腿人妻九九| 国产亚洲精品无码三区| 91欧美综合在线| 久草免费在线一区二区| 久久久啊啊啊| 蜜伊人色综合97| 在线观看高清AV| 97爱碰| 人人插人人搞人人操| 国产嫩草精品A88AV| 99热精品在线观看| 国产黄色视频久久| 91N综合网在线| 色色丁香| 天天射天天| 黄色十八禁| 久久久国产成人一区二区三区在线| 亚洲第一页色网| 亚洲自拍97| 91网站18+| 91美女高潮| 日熟女| 和协影院中文字幕三区| 国产乱不卡| 大香蕉伊人网| 色香91| 青娱乐黄色录像| 一本大道不卡一二三区| 国产一区二区三区,在线观看观看 五月开心久久AV官网 | 国产黄色剧情影片麻豆免费播放| 五月天伊人| 国产一级作爱毛片| 欲香欲色| 亚州五月| 动漫av中文| 五月香婷婷| 大二网站亚洲| 久久久久久人体| 日日AV加勒比| 99这里都是精品| 91人妻精华帖| 久操视频这里只有精品| 亚洲 欧美 另类 日韩 人妻一区| 色999五月色| 日韩中文字幕精品一区在线| 久久东京热成人| 国产成人主播| 99爱久久视频频| 操逼网站视频漫画国产| 欧美人与动性人交a| 精品久操| 精品二999| 国产不卡精品91| 免费一级毛片在线视频观看| 高清国产性猛交xxxx乱大交| 污色区网站| 91天天爽| 日韩av电影网站| av午夜玫瑰| 人妻少妇精品一区二区三区| 国产激情在线观看| 一本久道在线综合视频| 日韩操啪| 精品无码一区二区三区色欲| 国产三级片在线观看| 国产日韩中文字幕欧美| 嗯嗯啊啊好疼| 青青操少妇| 久久久久久亚洲精品中文字幕人妻| 天天激色| 欧美综合 站| 欧美日韩国产男人| 欧美 青青草| 亚洲人在线成线成人| 亚洲欧美精品一区天堂久久 | 久9久9精品| 欧美狠狠弄| 亚洲综合影视| 麻豆人妻少妇在线免费观看| 嗯嗯嗯啊啊啊操的我好爽 | 免费视频观看60秒| 国产嫩草精品A88AV| 蜜桃臀久久| 内射中国少妇高清视频免费视频 | 亚洲天堂精品日韩电影| 神马九九| 久久中文字幕一区不卡| 国产久久成人| 嫩草影院在线观看精品| 国产综合永久精品日韩鬼片| 久草免费在线一区二区| 欧美精品1区2区3区| 亚洲成?V人片在线观看福利| 国产精品电影| 99热免费| baiduhicn.com。| 久九9精品| 精品白丝一区| 麻豆精品一区二区三区四区免费观看| 在线日韩日本亚洲国产| 在线岛国新天堂8| 国产传媒操逼视频| 欧美色五月| 色噜噜综合在线| 蜜桃臀 后入 一区 二区 三区 在线| 四虎影库国产精品免费| 欧美亚洲涩涩| 新91视频.cmp| 欧美熟妇成人一区二区| 日本性爱不卡视频| 粉嫩国产精品久久粉嫩| 日韩免费高清大片在线| 家庭乱伦性爱av| 日韩在线观看中文字幕视频| 亚洲一区二区三区久久 亚洲一区二区| 国产极品999| 97欧美日韩中文| 天堂性色| 尤物网址| AV中文在线可看| 成人片视频| 97超碰超| 亚洲av综合色区无码一| 超碰亚洲97| 操曰本熟女| 日本一区二区三区四区五区六区七区八区九区| 熟女激情综合网| 欧美99热| 九九热精彩视频| 俞拍久久国应视频| 久操网线| 国产精品小视频一区二区三区| 欧美激情久久久久| 日韩无码人妻| 九九热九九| av72网| 欧美精品宗合| 热九九精品| 久草男人天堂| 色色毛片| 亚洲熟妇极品| 九九九999久久久网站| 五月婷网站| 四虎AV无码| 夜夜高潮夜夜爽夜夜爱爱一区 | 99操| 丁香婷婷五月| 精品超碰中文在线| 91综合天天看| 国产精品蜜乳AV| 亚洲熟女乱熟乱熟妇综合网二区| 亚洲国产综合图区中文字幕 | 97视频免费播放| 5278欧美一区二区三区| www被窝色com| 岛国片在线视频网站| 91人人爽人人爽人人人,gav福利视频导航,日韩欧美亚洲国产字幕四区 | 日本黄大片在线观看视频| 久久综合九九| 97精品人妻一二三四| 五月丁香拍拍激情综合三级| 在线黄色污污网站| 大屁股人妻女教师撅着屁股| 国产极品999| 国产精品剧情| 日本91白丝| 天美91| 夜夜中出国产| 永久免费观看的毛片的网站| 神马视频久久久久久| 国产精品香蕉| 91天天日| 亚欧毛片基地国产毛片基地| 国产又大又粗又长视频在线| 中文AV制服乱伦| 欧美亚洲一区二区久久久婷精品大包诱| 国产老女人久久毛| 亚洲AV资源| 欧美日韩另类在线播放| 97精品国产手机| 亚洲αv一区二区三区| 色妇91| 精品一区二区人妖| 老司机香蕉| 天天影视色香色欲| 国产成人91一区二区三区| 97色论| 欧美经典一区二区三区| 伦理日韩国产久久| 亚洲综合色网| 在线日韩精品一区二区三区| 一区| 性做久久久久久免费观看软件| 一卡二卡在线播放| 天美av在线观看| 小日子操bb在线看| 久久久月天| 国产最新AV| 国产一区二区a毛片| 91欧美少妇| 欧美激情亚洲色图| 精品成人动漫一区二区| 97在线播放| 91网站18| 97超级色碰碰| 91欧美高清| 天天躁日日躁xxxxx| julia国产在线| www.一本大99| 欧美精品自慰系列寂寞少妇 | 无码又爽又硬又激情免费视频| 人人模人人看| 热热色综合网| 高树玛利亚无码流出| 男人a天堂手机在线版| 婷婷午夜清品久久久久久久性色视频观| 国产夜夜艹| 爽 好舒服 无码刺激久久| 国产色产精品在线观看 | 太久视频| 欧州一区二区三区四区| 亚欧美色图| 蜜臀亚洲中文| 亚洲国产一区二区三区四区国产| 欧美亚洲自拍另类人妻| 亚洲91射| 亚洲诱惑| 日韩精彩免费| 色色色网站| 极品尤物女神在线观看| 秋霞网无码| 91老司机精品| 狠狠干妹子| 伊人丝袜美腿高跟在线观看高清| 婷婷在线播放| 黄片直播三级黄片两女一男| 国产精品第一区第一页| 综合色区偷拍| 中文无线日韩一区| 999综合色| 熟妇人妻一区二区| 天天综合,91综合永久| 黄色毛片A片| 无套内射人妻在线播放| 999久久久免费精品国产牛牛| 90后后入| 精品人妻一区二区蜜桃视频 | 性爱乱伦一区| 顶级丝袜熟女一区二区三区| 日韩中文字幕视频| 屁股久久久久久久| 超碰97人妻在线| 久草免费在线视频| 99热精品在线观看| 亚洲成人久久美女| 少妇高潮对白在线观看| 久草国产在线视频| 亚洲av影音先锋| 欧美性爱日韩性爱| 国模不卡| 国产精品自在线发布| 亚洲成人免费中文字幕| 操逼www.| 日韩欧美中文| 亚洲少妇中文字幕网址| 天天躁日日躁AAA片李宗瑞| 老熟女乱子伦中文字幕一区二区| 日韩无码三级影院| 欧美日日操| 天天看天天在线精品| 精品一区二区在线针对华人免费观看这里只有精品免费观看 | 91jk色拍| 伊人991| 欧美色图在线视频少妇| 天天干人妻视频| 97超碰精品图片| 少妇熟女一区二区三区| 亚洲图片欧美色| 日本一区二区亚洲综合| 国产精品爱欲| 囯产乱伦一区二区三女| 亚洲激情四射| 日韩AV一区二区三区三州三州| 伊人成人情色综合| 欧美亚州综合图片| 后入式福利| 中文乱码字幕观看| 中文字幕五月婷婷免费| 久久精品国产96精品亚洲拳交| 九九色热| 九九热五区| 精吧天堂| 中文字幕乱亚洲美女精品一区| 久久精品国产亚洲5555| 日本免费人成视频播放120秒| AV不卡在线| 精品久久一区二区三区四区五区| 一区二区三区男女操逼黄色小电影| 欧美在线55555| 青青草在线视频播放器| 日本人妻最新在线中| 久久九九视频九九视频| 男人的天堂网免费| 美美91成人国产精品欧美精品久久久久久久| 人妻熟女一区二区| 久久超碰网| 操操逼操操逼操操逼逼| 日韩精品一二三| 激情 欧美 亚洲 小说| 天美麻花大全视频| 99xav| 农村妇女精品一二区| 午夜福利激情在线视频| 91一区二区| 性交一区二区在线播放| 中文久久久| 青草青草久热| 久久av网| 久久无码精品| 夜色AV无码手机在线影院| 在线观看十八禁| 青草伊人网| 亚洲 自拍偷拍 欧美| 免费看毛片操穴| 人人摸人人舔一区二区| 超碰精品国产无码| 人妻啊啊人妻啊| 国产精品69久久久久久久| 国产丝袜欧美在线视频| 床上啊啊啊一区二区三区| 劲爆欧美人妖三区91| 日韩熟女无码| 欧美极品女人的天堂| 熟女91网| 淫荡熟女乱伦网| 日韩三级在线观看mp4| 少妇一区二区三区| 超碰av在线| q2午夜理论片夜色av| 人妻啪| 97 超碰 人人做 人人爱| 91性感在线| 久久九九99| 青青青草原| 香蕉人人操tv| 亚洲少妇激情一区二区三区| 欧美aa一级片| 国产精品高潮久久AV| 视频国产成人精品日本亚洲18| 伊人网av| 96久久久久| 屌色在线97视频| 亚洲色图A| 成人黑料社久久| 国产熟码AV| 欧美日韩国产色图在线| 91碰碰| 在线观看国产黄色| 女上位精品在线| 无码人妻丰满热妇又大又粗| 亚洲素人网| 蜜乳性色无码专日粉嫩骚逼AV| 嗯嗯啊啊视频一区二区三区| 正在播放国产精品一区| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 免费啪啪啪网站18岁| AV色五月| av在线资源| 啊啊啊啊啊啊啊啊在线观看| 六六久久日韩不卡| 青青草中文字幕| 欧美日韩理论一区| 日韩精品在线视频在线观看| 四虎在线播放| 一个人免费HD91视频| 97视频一区| 日本久操视频| 天天激情综合站| ...日韩成人一区二区三区字幕| 久久亚洲AV成人精品无码| 欧美日韩精品青青| 99热思思| 操人人| 亚洲偷91色| 久久精品小视频| 极品销魂美女一区二区| 97视频900| 久久婷综合| 2024黄色视频| 日本高清熟女久久一区| 国模精品一区二区三区苹果色戒| 人妻欧美| 天天舔九色婷婷| 久久久久国产一区二| 亚洲在饯| 新视频sss国产| 国产激情久久久| 夜夜操美女| 热G综合热G中文| 亚熟在线| 中文字幕 国产区| 日本久久女同性恋视频| 嗯嗯啊啊啊啊轻点视频| 日韩精品 资源| 性爱边摸边日免费AV| 久久久青青草| 精品人妻一区二区三区视频| 99色色网| 中文字幕国产| 国产一区二区在线播放| 久久大精品乱码视频人妻熟女| 婷婷导航| 久久国产热视频97电影| 我要色综合网| 蜜臀一二三区| 青青草五月天| 青青操青娱乐| 丰满的三级少妇欧美久久久| 五月丁香黄色网| 久久久免费高清中文视频| 日本丝袜美腿人妻九九| 婷婷久久久| 无码WWW免费视频网站| 色牛aV| 99热婷婷| 乱欲一区二区| 国产成人99久久亚洲综合| 99夜夜操| 97国产精品在线观看| 天美传媒在线一区| 嗯嗯嗯啊啊啊操的我好爽| 综合久| 亚洲最大网站av| 园内精品自拍视频在线播放| 97欧美超碰| 九九九国产| 国产自偷| 91男同| 久草在| 天美一二三在线观看Av| AV天天在线观看| 正在播放:深夜激情大战,自带黑丝袜全力输出骚穴 | 人妻三级在线中文字幕| 亚洲色图欧美色18直播在线| 国产av色网| 日韩色女精品| 97超碰中文| 60秒免费小视频| 精品人妻一区二区乱码一区二区| 999久久久九| 国产四虎在线| 99中出在线| 久久久影院| 日韩专区数据列表-第3230页-精品国产一区二区三区香蕉 久久99熟女人妻中文字 | 欧美在线电影| 天堂网亚洲区手机版| 天堂av最新电影网| 欧美最婬乱婬爆婬牲视频| 大干人妻| 亚洲丝袜二区在线| 久久香蕉国产线看观看亚洲女人 | 精品国产一区二区久久| 欧美78p| 韩国女主播青草福利视频| 久久久久无码| 78p欧美| www.AV有限公司一区| 最新av中文字幕高清| 男人的天堂午夜av| 久久91视频| 乱伦av.com| 91精品久久综合熟女| 97在线精品| 素人播放一区| 欧美天天谢综合网| 亚洲大色堂| 操曰本熟女| 日韩精品人妻中文字幕不卡乱码| 天天干夜夜鈤| 97色网| 自怕偷自怕亚洲精品| 伊人网综合在线视频| 日韩黄色电影网站| 久久精品欧美一区蜜桃| 久久久久一本一区二区青青蜜月| 好好的日:com久久九九| 91精品久久久久久77777| 18精品一二区| 人人搞人人插人人操| 中文人妻av高清一区| 强奸乱伦av电影| 日本在线一二| 加勒比综合九九99视频在线播放| 人妻熟女一区二区| 性91| 无码外流操逼视频| 亚洲AV成人无码一区二区三区在线观看 | 蜜臀人妻少妇久久在线观看| 97av,com| 欧美人妻少妇| 成人性爱视频在线看| 色婷五月| 国产AV人人 夜夜人人澡| 9997se| 青娱乐国产剧情av一区| 国产尤物AV尤物在线观看不卡| 天天爽天天爽| 狠狠2050在线观看| 精品久久久久久久| 黑人嘿嘿嘿超爽免费视频| 伊人五月天| 97一本大道亚洲一区| 久久人妻熟女一区二区 | 青青草无码视频| 99人妻| 黄色视频特级毛片| 久草视频制服诱惑| 欧美激情 亚洲色图| 岛国大片国产| 亚洲国产精品久久久久久久久久| 欧亚成人在线视频| 亚洲一区二区在线观看91| 日韩欧美俄罗斯A片| 日韩熟女精品无码专区一区二区| 日本97久久| 在线无码网站| 四虎永久在线精品免费网址| 91天天综合在线观看| 国产又黄又粗的视频| 激情自拍 校园春色| 丰满熟女人妻一区二区三五十一路| 日韩精品资源专区二区| 99热最新网址| 日韩中文字幕精品一二三事国产精品| 婷婷久久五月综合激情| 99热精品在线播放| 啊啊啊好疼| 小视频玖玖| 国产a级精品| 久久一二三四| A V少妇特黄三级| www.人人摸在线视频| 口爆吞精在线观看| 日韩午夜国产| 国产综合色精品在线观看| 天天操夜夜操| 91欧美www| 色综合色欲色综合色综合色综合| 久久久免费懂色| 国产日韩精品人妻久久久久色欲网站| 骚乳在线| 激情小说亚洲色图| 极品五月天噜噜| 人妻铁牛TV| 伊人AAA| 亚洲 在线| 婷婷色在线| 天天爱天天操| 精品精品精品| 老熟女91| 禁止观看美女黄| 91精品人| 刺激精品视频| 无码 黑人一区二区三区| 加勒比AV网| 另类TS人妖一区二区三区| 欧美曰韩国产精品| 八戒午夜福利理论片| 99xav| 很黄很色的视频在线观看| 男人把坤坤插入女人的下体| 不卡一区二区日本视频| 91无摭挡| 五月婷婷爱六月丁香色| 俞拍久久国应视频| AV色天香在线| 牛牛操视频逼| 4虎在线视频| 女人被添高潮免费视频| 亚洲中文字幕一区二区| 超碰97欧美在线| 精品美女久久久久| x97av| 婷婷操逼| 91内射| 麻豆伊人网| 91麻豆va国产精品| 欧美高清第一页| 国产一级久久久| 岛国片国产成人亚洲播放| 黑丝制服中文字幕 | 色99999| 96免费视频在线| 一级久久性爱视频| 91网站18禁| 亚洲成人色情五月天丁香花| 俺去俺来也在线www| 神马午夜久久| 日韩 成人 有码| 亚洲人妻AV| 欧美综合国产精品久久丁香| 搡老女人老91妇女熟女| 激情文学网伊人| 欧美日韩另类在线播放| 久久久999国产精品| 99r九九| 韩日无码在线观看| 欧美色图片| 伊人少妇久久久| 大香蕉AV丝袜| 懂色AV蜜臀无码精品APP| 懂色aV一区二区天美传媒| 久久少妇人妻| 91精品国产综合久久久蜜臀| 美女写真| 久久精品国产亚洲AV先锋| 超碰97导航| 欧美中文字幕一区 | 欧美天堂亚洲电影院一区在线播放| 337p大胆噜噜噜噜噜91Av| 色欲久久久久综合网| 亚洲欧洲日韩中文字幕一区| 熟女自慰久久久| 亚洲五月丁香花狠狠干一区二区三区 | 啊啊啊爽爽| 大香蕉92| 欧美色997| 大奶啊啊好爽 | 五月天色图| 丁香六月婷婷| 日韩探花精品在线视频| 亚洲欧美日韩制服另类| 香港久久久| 91熟女.com| 久操大香蕉超碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰 | av天堂精品久久| 91丝袜在线观看| 亚洲一区二区av| 久久久神马影院| 91天美传媒在线观看| 久久一区无码| 中文字幕在线观看丝袜| av天堂手机版追回 | 夜夜操夜夜爽夜夜高潮| 涩五月婷婷| 久精品无码av一区二免费国产在线观看| 97精品一区二区视频| 91亚洲欧洲| 91综合网在线| 精品日韩产品在线,日韩在线不卡视频,欧美日韩免费专区/久, | 99国产精品| 欧美毛片在线网| 青娱乐 青青青操 日逼| 五月天婷婷综合网| 国产欧美亚洲精品a第2页| 久久久青青草| 精品射1999| 欧美.亚洲.另类.丝袜.制服.诱惑| 五月天色色网站| 中文字幕日本久久| 黄色一级视| 国产精品午夜高潮呻吟久久av| 日本东京热加勒比久久| 免费精品福利在线观看| yiren97| 欧美三级一级| 射丝袜高跟鞋99| 人妻日日夜夜精品| 欧美精品另类人妖xxxx| 天天流夜夜操| 一区二区你上我| 超碰久久中文| 1024亚洲中文字幕久在线看片你懂的 | 久草精品视频| 亚洲自拍欧美色综合| 亚州熟妇精品| 九热超碰| 蜜桃久久一区| 久久久久久久9| 国产午夜精品在线观看| 精品一区二区三区免费古装毛片香港三级日本三级人妇 | 亚洲日韩国产欧美综合v| 亚洲精品乱码久久久久久蜜桃麻豆|