午夜视频免费看_日韩三级电影网站_国产精品久久一级_亚洲一级在线播放_人妻体内射精一区二区三区_91夜夜揉人人捏人人添红杏_91福利在线导航_国产又粗又猛又黄又爽无遮挡_欧美日韩一区在线播放_中文字幕一区二区三区四区不卡 _日日夜夜精品视频免费观看_欧美韩日一区二区三区

主頁 > 知識庫 > 深度解密 Go 語言中的 sync.map

深度解密 Go 語言中的 sync.map

熱門標簽:智能電銷機器人營銷 賺地圖標注的錢犯法嗎 地圖標注測試 福州鐵通自動外呼系統 長沙ai機器人電銷 廣東語音外呼系統供應商 澳門防封電銷卡 濮陽自動外呼系統代理 烏魯木齊人工電銷機器人系統

工作中,經常會碰到并發讀寫 map 而造成 panic 的情況,為什么在并發讀寫的時候,會 panic 呢?因為在并發讀寫的情況下,map 里的數據會被寫亂,之后就是 Garbage in, garbage out,還不如直接 panic 了。

是什么

Go 語言原生 map 并不是線程安全的,對它進行并發讀寫操作的時候,需要加鎖。而 sync.map 則是一種并發安全的 map,在 Go 1.9 引入。

sync.map 是線程安全的,讀取,插入,刪除也都保持著常數級的時間復雜度。
sync.map 的零值是有效的,并且零值是一個空的 map。在第一次使用之后,不允許被拷貝。

有什么用

一般情況下解決并發讀寫 map 的思路是加一把大鎖,或者把一個 map 分成若干個小 map,對 key 進行哈希,只操作相應的小 map。前者鎖的粒度比較大,影響效率;后者實現起來比較復雜,容易出錯。

而使用 sync.map 之后,對 map 的讀寫,不需要加鎖。并且它通過空間換時間的方式,使用 read 和 dirty 兩個 map 來進行讀寫分離,降低鎖時間來提高效率。

如何使用

使用非常簡單,和普通 map 相比,僅遍歷的方式略有區別:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map
	// 1. 寫入
	m.Store("qcrao", 18)
	m.Store("stefno", 20)

	// 2. 讀取
	age, _ := m.Load("qcrao")
	fmt.Println(age.(int))

	// 3. 遍歷
	m.Range(func(key, value interface{}) bool {
		name := key.(string)
		age := value.(int)
		fmt.Println(name, age)
		return true
	})

	// 4. 刪除
	m.Delete("qcrao")
	age, ok := m.Load("qcrao")
	fmt.Println(age, ok)

	// 5. 讀取或寫入
	m.LoadOrStore("stefno", 100)
	age, _ = m.Load("stefno")
	fmt.Println(age)
}

第 1 步,寫入兩個 k-v 對;

第 2 步,使用 Load 方法讀取其中的一個 key;

第 3 步,遍歷所有的 k-v 對,并打印出來;

第 4 步,刪除其中的一個 key,再讀這個 key,得到的就是 nil;

第 5 步,使用 LoadOrStore,嘗試讀取或寫入 "Stefno",因為這個 key 已經存在,因此寫入不成功,并且讀出原值。

程序輸出:

18
stefno 20
qcrao 18
nil> false
20

sync.map 適用于讀多寫少的場景。對于寫多的場景,會導致 read map 緩存失效,需要加鎖,導致沖突變多;而且由于未命中 read map 次數過多,導致 dirty map 提升為 read map,這是一個 O(N) 的操作,會進一步降低性能。

源碼分析

數據結構

先來看下 map 的數據結構。去掉大段的注釋后:

type Map struct {
	mu Mutex
	read atomic.Value // readOnly
	dirty map[interface{}]*entry
	misses int
}

互斥量 mu 保護 read 和 dirty。

read 是 atomic.Value 類型,可以并發地讀。但如果需要更新 read,則需要加鎖保護。對于 read 中存儲的 entry 字段,可能會被并發地 CAS 更新。但是如果要更新一個之前已被刪除的 entry,則需要先將其狀態從 expunged 改為 nil,再拷貝到 dirty 中,然后再更新。

dirty 是一個非線程安全的原始 map。包含新寫入的 key,并且包含 read 中的所有未被刪除的 key。這樣,可以快速地將 dirty 提升為 read 對外提供服務。如果 dirty 為 nil,那么下一次寫入時,會新建一個新的 dirty,這個初始的 dirtyread 的一個拷貝,但除掉了其中已被刪除的 key。

每當從 read 中讀取失敗,都會將 misses 的計數值加 1,當加到一定閾值以后,需要將 dirty 提升為 read,以期減少 miss 的情形。

read mapdirty map 的存儲方式是不一致的。
前者使用 atomic.Value,后者只是單純的使用 map。
原因是 read map 使用 lock free 操作,必須保證 load/store 的原子性;而 dirty map 的 load+store 操作是由 lock(就是 mu)來保護的。

真正存儲 key/value 的是 read 和 dirty 字段。read 使用 atomic.Value,這是 lock-free 的基礎,保證 load/store 的原子性。dirty 則直接用了一個原始的 map,對于它的 load/store 操作需要加鎖。

read 字段里實際上是存儲的是:

// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnly struct {
	m  map[interface{}]*entry
	amended bool // true if the dirty map contains some key not in m.
}

注意到 read 和 dirty 里存儲的東西都包含 entry,來看一下:

type entry struct {
	p unsafe.Pointer // *interface{}
}

很簡單,它是一個指針,指向 value??磥恚瑀ead 和 dirty 各自維護一套 key,key 指向的都是同一個 value。也就是說,只要修改了這個 entry,對 read 和 dirty 都是可見的。這個指針的狀態有三種:

p == nil 時,說明這個鍵值對已被刪除,并且 m.dirty == nil,或 m.dirty[k] 指向該 entry。

p == expunged 時,說明這條鍵值對已被刪除,并且 m.dirty != nil,且 m.dirty 中沒有這個 key。

其他情況,p 指向一個正常的值,表示實際 interface{} 的地址,并且被記錄在 m.read.m[key] 中。如果這時 m.dirty 不為 nil,那么它也被記錄在 m.dirty[key] 中。兩者實際上指向的是同一個值。

當刪除 key 時,并不實際刪除。一個 entry 可以通過原子地(CAS 操作)設置 p 為 nil 被刪除。如果之后創建 m.dirty,nil 又會被原子地設置為 expunged,且不會拷貝到 dirty 中。

如果 p 不為 expunged,和 entry 相關聯的這個 value 可以被原子地更新;如果 p == expunged,那么僅當它初次被設置到 m.dirty 之后,才可以被更新。

整體用一張圖來表示:

Store

先來看 expunged:

var expunged = unsafe.Pointer(new(interface{}))

它是一個指向任意類型的指針,用來標記從 dirty map 中刪除的 entry。

// Store sets the value for a key.
func (m *Map) Store(key, value interface{}) {
	// 如果 read map 中存在該 key 則嘗試直接更改(由于修改的是 entry 內部的 pointer,因此 dirty map 也可見)
	read, _ := m.read.Load().(readOnly)
	if e, ok := read.m[key]; ok  e.tryStore(value) {
		return
	}

	m.mu.Lock()
	read, _ = m.read.Load().(readOnly)
	if e, ok := read.m[key]; ok {
		if e.unexpungeLocked() {
			// 如果 read map 中存在該 key,但 p == expunged,則說明 m.dirty != nil 并且 m.dirty 中不存在該 key 值 此時:
			// a. 將 p 的狀態由 expunged 更改為 nil
			// b. dirty map 插入 key
			m.dirty[key] = e
		}
		// 更新 entry.p = value (read map 和 dirty map 指向同一個 entry)
		e.storeLocked(value)
	} else if e, ok := m.dirty[key]; ok {
		// 如果 read map 中不存在該 key,但 dirty map 中存在該 key,直接寫入更新 entry(read map 中仍然沒有這個 key)
		e.storeLocked(value)
	} else {
		// 如果 read map 和 dirty map 中都不存在該 key,則:
		//	 a. 如果 dirty map 為空,則需要創建 dirty map,并從 read map 中拷貝未刪除的元素到新創建的 dirty map
		// b. 更新 amended 字段,標識 dirty map 中存在 read map 中沒有的 key
		// c. 將 kv 寫入 dirty map 中,read 不變
		if !read.amended {
		 // 到這里就意味著,當前的 key 是第一次被加到 dirty map 中。
			// store 之前先判斷一下 dirty map 是否為空,如果為空,就把 read map 淺拷貝一次。
			m.dirtyLocked()
			m.read.Store(readOnly{m: read.m, amended: true})
		}
		// 寫入新 key,在 dirty 中存儲 value
		m.dirty[key] = newEntry(value)
	}
	m.mu.Unlock()
}

整體流程:

  • 如果在 read 里能夠找到待存儲的 key,并且對應的 entry 的 p 值不為 expunged,也就是沒被刪除時,直接更新對應的 entry 即可。
  • 第一步沒有成功:要么 read 中沒有這個 key,要么 key 被標記為刪除。則先加鎖,再進行后續的操作。
  • 再次在 read 中查找是否存在這個 key,也就是 double check 一下,這也是 lock-free 編程里的常見套路。如果 read 中存在該 key,但 p == expunged,說明 m.dirty != nil 并且 m.dirty 中不存在該 key 值 此時: a. 將 p 的狀態由 expunged 更改為 nil;b. dirty map 插入 key。然后,直接更新對應的 value。
  • 如果 read 中沒有此 key,那就查看 dirty 中是否有此 key,如果有,則直接更新對應的 value,這時 read 中還是沒有此 key。
  • 最后一步,如果 read 和 dirty 中都不存在該 key,則:a. 如果 dirty 為空,則需要創建 dirty,并從 read 中拷貝未被刪除的元素;b. 更新 amended 字段,標識 dirty map 中存在 read map 中沒有的 key;c. 將 k-v 寫入 dirty map 中,read.m 不變。最后,更新此 key 對應的 value。

再來看一些子函數:

// 如果 entry 沒被刪,tryStore 存儲值到 entry 中。如果 p == expunged,即 entry 被刪,那么返回 false。
func (e *entry) tryStore(i *interface{}) bool {
	for {
		p := atomic.LoadPointer(e.p)
		if p == expunged {
			return false
		}
		if atomic.CompareAndSwapPointer(e.p, p, unsafe.Pointer(i)) {
			return true
		}
	}
}

tryStore 在 Store 函數最開始的時候就會調用,是比較常見的 for 循環加 CAS 操作,嘗試更新 entry,讓 p 指向新的值。

unexpungeLocked 函數確保了 entry 沒有被標記成已被清除:

// unexpungeLocked 函數確保了 entry 沒有被標記成已被清除。
// 如果 entry 先前被清除過了,那么在 mutex 解鎖之前,它一定要被加入到 dirty map 中
func (e *entry) unexpungeLocked() (wasExpunged bool) {
	return atomic.CompareAndSwapPointer(e.p, expunged, nil)
}

Load

func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	// 如果沒在 read 中找到,并且 amended 為 true,即 dirty 中存在 read 中沒有的 key
	if !ok  read.amended {
		m.mu.Lock() // dirty map 不是線程安全的,所以需要加上互斥鎖
		// double check。避免在上鎖的過程中 dirty map 提升為 read map。
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		// 仍然沒有在 read 中找到這個 key,并且 amended 為 true
		if !ok  read.amended {
			e, ok = m.dirty[key] // 從 dirty 中找
			// 不管 dirty 中有沒有找到,都要"記一筆",因為在 dirty 提升為 read 之前,都會進入這條路徑
			m.missLocked()
		}
		m.mu.Unlock()
	}
	if !ok { // 如果沒找到,返回空,false
		return nil, false
	}
	return e.load()
}

處理路徑分為 fast path 和 slow path,整體流程如下:

  • 首先是 fast path,直接在 read 中找,如果找到了直接調用 entry 的 load 方法,取出其中的值。
  • 如果 read 中沒有這個 key,且 amended 為 fase,說明 dirty 為空,那直接返回 空和 false。
  • 如果 read 中沒有這個 key,且 amended 為 true,說明 dirty 中可能存在我們要找的 key。當然要先上鎖,再嘗試去 dirty 中查找。在這之前,仍然有一個 double check 的操作。若還是沒有在 read 中找到,那么就從 dirty 中找。不管 dirty 中有沒有找到,都要"記一筆",因為在 dirty 被提升為 read 之前,都會進入這條路徑

這里主要看下 missLocked 的函數的實現:

func (m *Map) missLocked() {
	m.misses++
	if m.misses  len(m.dirty) {
		return
	}
	// dirty map 晉升
	m.read.Store(readOnly{m: m.dirty})
	m.dirty = nil
	m.misses = 0
}

直接將 misses 的值加 1,表示一次未命中,如果 misses 值小于 m.dirty 的長度,就直接返回。否則,將 m.dirty 晉升為 read,并清空 dirty,清空 misses 計數值。這樣,之前一段時間新加入的 key 都會進入到 read 中,從而能夠提升 read 的命中率。

再來看下 entry 的 load 方法:

func (e *entry) load() (value interface{}, ok bool) {
	p := atomic.LoadPointer(e.p)
	if p == nil || p == expunged {
		return nil, false
	}
	return *(*interface{})(p), true
}

對于 nil 和 expunged 狀態的 entry,直接返回 ok=false;否則,將 p 轉成 interface{} 返回。

Delete

// Delete deletes the value for a key.
func (m *Map) Delete(key interface{}) {
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	// 如果 read 中沒有這個 key,且 dirty map 不為空
	if !ok  read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		if !ok  read.amended {
			delete(m.dirty, key) // 直接從 dirty 中刪除這個 key
		}
		m.mu.Unlock()
	}
	if ok {
		e.delete() // 如果在 read 中找到了這個 key,將 p 置為 nil
	}
}

可以看到,基本套路還是和 Load,Store 類似,都是先從 read 里查是否有這個 key,如果有則執行 entry.delete 方法,將 p 置為 nil,這樣 read 和 dirty 都能看到這個變化。

如果沒在 read 中找到這個 key,并且 dirty 不為空,那么就要操作 dirty 了,操作之前,還是要先上鎖。然后進行 double check,如果仍然沒有在 read 里找到此 key,則從 dirty 中刪掉這個 key。但不是真正地從 dirty 中刪除,而是更新 entry 的狀態。

來看下 entry.delete 方法:

func (e *entry) delete() (hadValue bool) {
	for {
		p := atomic.LoadPointer(e.p)
		if p == nil || p == expunged {
			return false
		}
		if atomic.CompareAndSwapPointer(e.p, p, nil) {
			return true
		}
	}
}

它真正做的事情是將正常狀態(指向一個 interface{})的 p 設置成 nil。沒有設置成 expunged 的原因是,當 p 為 expunged 時,表示它已經不在 dirty 中了。這是 p 的狀態機決定的,在 tryExpungeLocked 函數中,會將 nil 原子地設置成 expunged。

tryExpungeLocked 是在新創建 dirty 時調用的,會將已被刪除的 entry.p 從 nil 改成 expunged,這個 entry 就不會寫入 dirty 了。

func (e *entry) tryExpungeLocked() (isExpunged bool) {
	p := atomic.LoadPointer(e.p)
	for p == nil {
		// 如果原來是 nil,說明原 key 已被刪除,則將其轉為 expunged。
		if atomic.CompareAndSwapPointer(e.p, nil, expunged) {
			return true
		}
		p = atomic.LoadPointer(e.p)
	}
	return p == expunged
}

注意到如果 key 同時存在于 read 和 dirty 中時,刪除只是做了一個標記,將 p 置為 nil;而如果僅在 dirty 中含有這個 key 時,會直接刪除這個 key。原因在于,若兩者都存在這個 key,僅做標記刪除,可以在下次查找這個 key 時,命中 read,提升效率。若只有在 dirty 中存在時,read 起不到“緩存”的作用,直接刪除。

LoadOrStore

這個函數結合了 Load 和 Store 的功能,如果 map 中存在這個 key,那么返回這個 key 對應的 value;否則,將 key-value 存入 map。這在需要先執行 Load 查看某個 key 是否存在,之后再更新此 key 對應的 value 時很有效,因為 LoadOrStore 可以并發執行。

具體的過程不再一一分析了,可參考 Load 和 Store 的源碼分析。

Range

Range 的參數是一個函數:

f func(key, value interface{}) bool

由使用者提供實現,Range 將遍歷調用時刻 map 中的所有 k-v 對,將它們傳給 f 函數,如果 f 返回 false,將停止遍歷。

func (m *Map) Range(f func(key, value interface{}) bool) {
	read, _ := m.read.Load().(readOnly)
	if read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		if read.amended {
			read = readOnly{m: m.dirty}
			m.read.Store(read)
			m.dirty = nil
			m.misses = 0
		}
		m.mu.Unlock()
	}

	for k, e := range read.m {
		v, ok := e.load()
		if !ok {
			continue
		}
		if !f(k, v) {
			break
		}
	}
}

當 amended 為 true 時,說明 dirty 中含有 read 中沒有的 key,因為 Range 會遍歷所有的 key,是一個 O(n) 操作。將 dirty 提升為 read,會將開銷分攤開來,所以這里直接就提升了。

之后,遍歷 read,取出 entry 中的值,調用 f(k, v)。

其他

關于為何 sync.map 沒有 Len 方法,參考資料里給出了 issue,bcmills 認為對于并發的數據結構和非并發的數據結構并不一定要有相同的方法。例如,map 有 Len 方法,sync.map 卻不一定要有。就像 sync.map 有 LoadOrStore 方法,map 就沒有一樣。

有些實現增加了一個計數器,并原子地增加或減少它,以此來表示 sync.map 中元素的個數。但 bcmills 提出這會引入競爭:atomic 并不是 contention-free 的,它只是把競爭下沉到了 CPU 層級。這會給其他不需要 Len 方法的場景帶來負擔。

總結

  1. sync.map 是線程安全的,讀取,插入,刪除也都保持著常數級的時間復雜度。
  2. 通過讀寫分離,降低鎖時間來提高效率,適用于讀多寫少的場景。
  3. Range 操作需要提供一個函數,參數是 k,v,返回值是一個布爾值:f func(key, value interface{}) bool。
  4. 調用 Load 或 LoadOrStore 函數時,如果在 read 中沒有找到 key,則會將 misses 值原子地增加 1,當 misses 增加到和 dirty 的長度相等時,會將 dirty 提升為 read。以期減少“讀 miss”。
  5. 新寫入的 key 會保存到 dirty 中,如果這時 dirty 為 nil,就會先新創建一個 dirty,并將 read 中未被刪除的元素拷貝到 dirty。
  6. 當 dirty 為 nil 的時候,read 就代表 map 所有的數據;當 dirty 不為 nil 的時候,dirty 才代表 map 所有的數據。

參考資料

【德志大佬-設計并發安全的 map】https://halfrost.com/go_map_chapter_one/

【德志大佬-設計并發安全的 map】https://halfrost.com/go_map_chapter_two/

【關于 sync.map 為什么沒有 len 方法的 issue】https://github.com/golang/go/issues/20680

【芮神增加了 len 方法】http://xiaorui.cc/archives/4972

【圖解 map 操作】https://wudaijun.com/2018/02/go-sync-map-implement/

【從一道面試題開始】https://segmentfault.com/a/1190000018657984

【源碼分析】https://zhuanlan.zhihu.com/p/44585993

【行文通暢,流程圖清晰】https://juejin.im/post/5d36a7cbf265da1bb47da444

到此這篇關于深度解密 Go 語言中的 sync.map的文章就介紹到這了,更多相關Go 語言sync.map內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • golang中使用sync.Map的方法
  • golang中sync.Map并發創建、讀取問題實戰記錄
  • Go 并發讀寫 sync.map 詳細

標簽:慶陽 德州 西雙版納 廣西 太原 阿克蘇 調研邀請 貴陽

巨人網絡通訊聲明:本文標題《深度解密 Go 語言中的 sync.map》,本文關鍵詞  深度,解密,語言,中的,sync.map,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《深度解密 Go 語言中的 sync.map》相關的同類信息!
  • 本頁收集關于深度解密 Go 語言中的 sync.map的相關信息資訊供網民參考!
  • 推薦文章
    久久一日本道色综合久久| 亚洲女同二女同志奶水| 99久久久无码国产精品6| 九九热只有这里有精品| 五月天av在线播放| av无码av天天av天天爽| 成人免费视频网站入口::| 一级片视频在线观看| 九九九在线视频| 日本一区二区三区网站| 捆绑凌虐一区二区三区| 亚洲无人区码一码二码三码| 99热国产在线观看| 天堂影院一区二区| 国产成人精品一区二| 97久久超碰国产精品| www精品美女久久久tv| 国产欧美一区二区三区另类精品| 中文字幕你懂的| 日韩在线视频导航| 国产亚洲精品久久久久久无几年桃| av成人老司机| 亚洲一二三四在线观看| 日韩精品一区国产麻豆| 久久久久久久久久久人体| 国产精品美女主播| 中文字幕一区二区三区最新| 黄色一级片免费的| 日韩欧美123区| 国产又黄又爽视频| 99久久精品国产导航| 在线区一区二视频| 在线精品国产欧美| 91视频8mav| 欧美国产日韩激情| 波多野结衣a v在线| 在线观看黄色国产| 国产呦精品一区二区三区网站| 国产蜜臀97一区二区三区 | ww国产内射精品后入国产| 免费无码毛片一区二三区| 久久视频这里有精品| 国产精品第七页| 国内精品久久久久久久久久久| 91碰在线视频| 欧美久久久久免费| 亚洲国产精彩中文乱码av| 青草成人免费视频| 精品视频在线观看一区| 国产午夜精品美女毛片视频| 久久精品magnetxturnbtih| 狠狠久久亚洲欧美| 国产精品视频男人的天堂| 亚洲三区在线观看| 亚洲成a人片在线www| 亚洲免费激情视频| 高清av一区二区| 国产精品无圣光一区二区| 欧美成人艳星乳罩| 国产成人精品在线播放| 欧美亚洲另类色图| 国语对白一区二区| 蜜臀a∨国产成人精品| 亚洲成人av电影在线| 久热国产精品视频| 天天干天天操天天干天天操| 天天操天天干天天操天天干| 不卡视频免费在线观看| 18涩涩午夜精品.www| 欧美福利电影网| 一区二区三区天堂av| 国产精品午夜视频| 国产不卡一区二区在线观看 | 成人国产精品日本在线| 91在线播放观看| 亚洲国产91色在线| 国产无遮无挡120秒| 一区二区成人精品| 黄色性生活一级片| 欧美午夜电影在线| 国产日韩久久| 蜜臀视频一区二区三区| 九一国产在线观看| 成人av资源在线| 亚洲成人亚洲激情| 国产色综合一区二区三区| 国产 xxxx| 香蕉人妻av久久久久天天| 日本乱人伦一区| 国产精品福利久久久| 亚洲va在线va天堂va偷拍| 成人午夜福利视频| 色悠久久久久综合欧美99| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 亚洲成人国产精品| 2021国产精品视频| 色播五月综合| 国产免费看av| 自拍偷拍18p| 洋洋av久久久久久久一区| 成人一区二区三区四区| 男女全黄做爰文章| 久久久www免费人成精品| y97精品国产97久久久久久| 久久久影院一区二区三区| 91视频最新网址| 国产精品色眯眯| 亚洲怡红院在线| 制服丝袜成人动漫| 久久日免费视频| 欧美日韩国产限制| 国产精品高清在线| 亚洲第九十七页| 国产ts人妖一区二区| 久久视频在线观看免费| 99免费视频观看| 久久国产直播| 亚洲美女av在线| 黄黄视频在线观看| 中文字幕一区二区三区波野结| 8v天堂国产在线一区二区| 日本高清一区| 亚洲一区二区人妻| 欧美丰满一区二区免费视频| 亚洲色图都市激情| 欧美熟妇另类久久久久久不卡 | 日本美女一区二区三区视频| 欧美日韩国产一区| 精品久久sese| 少妇视频在线播放| 91美女蜜桃在线| 久色乳综合思思在线视频| 免费无码一区二区三区| 精品动漫一区二区三区| 国产一区一区三区| 蜜乳av一区二区| 中文字幕日韩欧美在线视频| 成人在线看视频| 成人精品小蝌蚪| 国产精品亚洲аv天堂网| 99久久久免费精品国产一区二区| 黄免费在线观看| 成人资源视频网站免费| 欧美性受xxxx黑人xyx| 黄色激情在线观看| 国产欧美一二三区| 国产成人成网站在线播放青青| 中文字字幕在线中文| 欧美日韩亚洲不卡| 国产精品www在线观看| 日韩精品一二三区| 欧美极品美女电影一区| 日韩精品一区二区三区在线视频| 亚洲成人第一页| 最新av网址在线观看| 久久久久久久久免费| 日产精品久久久一区二区福利| 一级成人免费视频| 成人黄色午夜影院| 日韩一级片在线播放| 国产综合一区二区| 国产精品无码午夜福利| 欧美国产一二三区| 精品久久在线播放| 成人激情四射网| 亚洲国产精品www| 一本色道亚洲精品aⅴ| 国内av一区二区| 亚洲精品视频二区| 国产美女www爽爽爽| 欧美亚洲一级二级| 美女在线视频一区| 久久精品成人一区二区三区蜜臀 | 欧美三日本三级少妇99| 日本久久91av| 蜜桃一区二区三区四区| 91视频最新入口| 日韩码欧中文字| 少妇高潮大叫好爽喷水| 精品国产一二三区| 精品视频一二三区| 青青青青草视频| 日本精品在线视频| 欧美日韩中文一区| 播五月开心婷婷综合| 国产在线一区视频| 国产毛片视频网站| 欧美激情欧美激情在线五月| 99久久国产综合色|国产精品| 日本黄大片一区二区三区| 欧美日韩亚洲不卡| 一本一道无码中文字幕精品热| 97操在线视频| 色噜噜夜夜夜综合网| 9191在线视频| 亚洲欧美日韩高清| 看片的网站亚洲| 99自拍偷拍视频| 久久久久久精| 欧美日韩亚洲一区二区三区| 91porny九色| 久久久婷婷一区二区三区不卡| 亚洲欧美日韩动漫| 日韩av自拍偷拍| 国内精品一区二区三区四区| 国产偷国产偷精品高清尤物| 福利在线一区二区三区| 国产精品亚洲自拍| 欧美一区二区三区日韩视频| 国产精品久久久久久久久图文区 | 久久99国内精品| 在线观看一区二区三区四区| 国产激情综合五月久久| 国产成人鲁色资源国产91色综| 一卡二卡三卡四卡| 国产精品美女主播| 色噜噜久久综合| 日韩欧美中文字幕一区二区| 成人欧美一区二区三区视频xxx | 噜噜噜在线视频| 国产精品人人做人人爽| 亚洲摸摸操操av| 国产精品无码粉嫩小泬| 日本伊人精品一区二区三区介绍| 精品久久久久久国产| 国产婷婷在线视频| 182午夜在线观看| 亚洲a在线观看| 欧美大片免费久久精品三p| 老司机精品视频在线| 久久久九九九热| 日韩性xxxx爱| 成人av网站在线观看| 91成年人网站| 欧美日韩免费高清| 亚洲天堂成人网| 日韩aaaaaa| 欧美国产二区| 97在线观看视频| 日韩久久精品电影| 欧美国产日韩精品免费观看| 特黄一区二区三区| 伊人色综合影院| 欧美大荫蒂xxx| 奇米精品一区二区三区四区| 日本新janpanese乱熟| 国产精品一久久香蕉国产线看观看| 欧美老人xxxx18| 亚洲少妇30p| 国产91丝袜在线播放九色| 成人毛片视频免费看| 永久免费无码av网站在线观看| 乳色吐息在线观看| 国精产品一区一区三区视频| 黄色www在线观看| 亚洲精品一区二区三区精华液 | 免费观看成人毛片| 999精品网站| 日韩大陆毛片av| 美女在线视频一区| 亚洲av人人澡人人爽人人夜夜| 欧美啪啪免费视频| 精品免费视频123区| 欧美激情精品久久久| 亚洲精品第一国产综合野| 国产精品女同一区二区| 六十路息与子猛烈交尾| 成人免费网站在线观看| 亚洲视频免费在线| 精品久久久久中文慕人妻| 强迫凌虐淫辱の牝奴在线观看| 色综合电影网| 亚洲a区在线视频| 国产成人高潮免费观看精品| 欧美精品做受xxx性少妇| 亚洲人成在线观看网站高清| 欧美成人vr18sexvr| 欧美日韩午夜激情| 一区二区三区在线免费视频| 国产精品1区二区.| 亚洲欧美综合另类| 四季av中文字幕| 奇米精品在线| 国产精品久久久久久久久久三级| 欧美精品久久99久久在免费线| 国产精品久久久久久久久搜平片| 日韩中文字幕免费在线观看| 狠狠操狠狠干视频| 国产高清一区视频| 亚洲午夜未满十八勿入免费观看全集| 熟妇高潮一区二区| 欧美成人三级在线播放| 自拍偷拍亚洲色图欧美| 97在线视频免费看| 欧美精品一区二区三区四区| 色综合久久中文字幕综合网| 国产精品正在播放| 91在线无精精品白丝| 亚洲狼人综合干| 青草全福视在线| 精品不卡在线| 欧美日产一区二区三区在线观看| 久精品国产欧美| 亚洲欧洲日韩综合二区| 桥本有菜av在线| 午夜精品久久久久久久无码| 少妇性l交大片| 爱爱爱爱免费视频| 91黄色小网站| 精品少妇人欧美激情在线观看| 日韩精品亚洲精品| 色噜噜狠狠色综合欧洲selulu | 免费成人深夜夜行网站| 国产一伦一伦一伦| 视色视频在线观看| 天堂精品一区二区三区| 欧美夫妻性生活xx| 日韩高清人体午夜| 这里只有精品免费| 欧美日韩国产区一| 欧美成人性福生活免费看| 亚洲精品videosex极品| 99精品国产91久久久久久 | 国产乱国产乱老熟300| 久久99中文字幕| 成人午夜黄色影院| 日本欧美黄网站| 国产91精品久久久久| 国内精品久久影院| 91在线观看免费| 久久精品ww人人做人人爽| 日韩欧美国产综合在线| 91精品国产三级| 亚洲 欧美 变态 另类 综合| 国产一级片免费| 在线免费观看日韩视频| 91午夜交换视频| 国产强伦人妻毛片| 亚洲熟妇无码乱子av电影| 黄色片视频免费| 欧美福利第一页| www久久久久久久| 变态另类丨国产精品| 国产男女猛烈无遮挡a片漫画| 国产又大又粗又爽的毛片| 国产伦精品一区二区三区妓女下载 | 精品无码一区二区三区电影桃花| 日韩乱码在线观看| 实拍女处破www免费看| 中国黄色a级片| 能免费看av的网站| 国产精品久久久精品四季影院| 日本黄色免费观看| 欧美日韩一区二区在线免费观看| 91最新国产视频| 91最新在线免费观看| 国产精品视频免费一区二区三区| 日韩在线观看成人| 色呦呦日韩精品| 国产日本亚洲高清| 久久久久99| 天天操夜夜操视频| 亚洲 欧美 变态 另类 综合| 一起操在线视频| 中国丰满人妻videoshd | 国产女人aaa级久久久级| 国产欧美久久久| 一区二区在线观看免费视频| 手机在线播放av| 日本女人高潮视频| 亚洲最大成人网色| 久久久久久一区二区三区| 亚洲第一在线视频| 欧美视频在线观看免费网址| 久久久电影一区二区三区| 爽好多水快深点欧美视频| 这里只有精品国产| 黄色一级视频免费观看| 亚洲av成人片无码| 婷婷激情5月天| 波多野结衣综合网| 手机在线看福利| www.日本一区| 一本加勒比波多野结衣| 中文在线一区二区三区| 男人的天堂久久久| 在线免费观看日韩视频| 91视频综合网| 538精品在线视频| 中文字幕久久网| 欧美brazzers| 天天干天天干天天干天天| 亚洲黄色小说网址| 99精品桃花视频在线观看| 日韩一级欧美一级| 成人深夜直播免费观看| 北条麻妃在线观看| 久久中文字幕在线观看| 黄网在线观看视频| 国产农村妇女毛片精品久久| 天天综合网在线| 青娱乐精品视频| 亚洲一区二区三区四区在线观看| 国产午夜精品全部视频播放| 国产一区精品视频| 午夜激情影院在线观看| 中国老头性行为xxxx| 国产精品久久久久一区二区三区| 亚洲国产中文字幕久久网| 国产伦精品一区二区|