成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

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

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

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

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

是什么

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

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

有什么用

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

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

如何使用

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

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. 讀取或?qū)懭?
	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,嘗試讀取或?qū)懭?"Stefno",因為這個 key 已經(jīng)存在,因此寫入不成功,并且讀出原值。

程序輸出:

18
stefno 20
qcrao 18
nil> false
20

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

源碼分析

數(shù)據(jù)結(jié)構(gòu)

先來看下 map 的數(shù)據(jù)結(jié)構(gòu)。去掉大段的注釋后:

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

互斥量 mu 保護 read 和 dirty。

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

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

每當從 read 中讀取失敗,都會將 misses 的計數(shù)值加 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 的基礎(chǔ),保證 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。看來,read 和 dirty 各自維護一套 key,key 指向的都是同一個 value。也就是說,只要修改了這個 entry,對 read 和 dirty 都是可見的。這個指針的狀態(tài)有三種:

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 操作)設(shè)置 p 為 nil 被刪除。如果之后創(chuàng)建 m.dirty,nil 又會被原子地設(shè)置為 expunged,且不會拷貝到 dirty 中。

如果 p 不為 expunged,和 entry 相關(guān)聯(lián)的這個 value 可以被原子地更新;如果 p == expunged,那么僅當它初次被設(shè)置到 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 內(nèi)部的 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 的狀態(tài)由 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 為空,則需要創(chuàng)建 dirty map,并從 read map 中拷貝未刪除的元素到新創(chuàng)建的 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,并且對應(yīng)的 entry 的 p 值不為 expunged,也就是沒被刪除時,直接更新對應(yīng)的 entry 即可。
  • 第一步?jīng)]有成功:要么 read 中沒有這個 key,要么 key 被標記為刪除。則先加鎖,再進行后續(xù)的操作。
  • 再次在 read 中查找是否存在這個 key,也就是 double check 一下,這也是 lock-free 編程里的常見套路。如果 read 中存在該 key,但 p == expunged,說明 m.dirty != nil 并且 m.dirty 中不存在該 key 值 此時: a. 將 p 的狀態(tài)由 expunged 更改為 nil;b. dirty map 插入 key。然后,直接更新對應(yīng)的 value。
  • 如果 read 中沒有此 key,那就查看 dirty 中是否有此 key,如果有,則直接更新對應(yīng)的 value,這時 read 中還是沒有此 key。
  • 最后一步,如果 read 和 dirty 中都不存在該 key,則:a. 如果 dirty 為空,則需要創(chuàng)建 dirty,并從 read 中拷貝未被刪除的元素;b. 更新 amended 字段,標識 dirty map 中存在 read map 中沒有的 key;c. 將 k-v 寫入 dirty map 中,read.m 不變。最后,更新此 key 對應(yīng)的 value。

再來看一些子函數(shù):

// 如果 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 函數(shù)最開始的時候就會調(diào)用,是比較常見的 for 循環(huán)加 CAS 操作,嘗試更新 entry,讓 p 指向新的值。

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

// unexpungeLocked 函數(shù)確保了 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 中找,如果找到了直接調(diào)用 entry 的 load 方法,取出其中的值。
  • 如果 read 中沒有這個 key,且 amended 為 fase,說明 dirty 為空,那直接返回 空和 false。
  • 如果 read 中沒有這個 key,且 amended 為 true,說明 dirty 中可能存在我們要找的 key。當然要先上鎖,再嘗試去 dirty 中查找。在這之前,仍然有一個 double check 的操作。若還是沒有在 read 中找到,那么就從 dirty 中找。不管 dirty 中有沒有找到,都要"記一筆",因為在 dirty 被提升為 read 之前,都會進入這條路徑

這里主要看下 missLocked 的函數(shù)的實現(xiàn):

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 計數(shù)值。這樣,之前一段時間新加入的 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 狀態(tài)的 entry,直接返回 ok=false;否則,將 p 轉(zhuǎn)成 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,如果有則執(zhí)行 entry.delete 方法,將 p 置為 nil,這樣 read 和 dirty 都能看到這個變化。

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

來看下 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
		}
	}
}

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

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

func (e *entry) tryExpungeLocked() (isExpunged bool) {
	p := atomic.LoadPointer(e.p)
	for p == nil {
		// 如果原來是 nil,說明原 key 已被刪除,則將其轉(zhuǎn)為 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

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

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

Range

Range 的參數(shù)是一個函數(shù):

f func(key, value interface{}) bool

由使用者提供實現(xiàn),Range 將遍歷調(diào)用時刻 map 中的所有 k-v 對,將它們傳給 f 函數(shù),如果 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 中的值,調(diào)用 f(k, v)。

其他

關(guān)于為何 sync.map 沒有 Len 方法,參考資料里給出了 issue,bcmills 認為對于并發(fā)的數(shù)據(jù)結(jié)構(gòu)和非并發(fā)的數(shù)據(jù)結(jié)構(gòu)并不一定要有相同的方法。例如,map 有 Len 方法,sync.map 卻不一定要有。就像 sync.map 有 LoadOrStore 方法,map 就沒有一樣。

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

總結(jié)

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

參考資料

【德志大佬-設(shè)計并發(fā)安全的 map】https://halfrost.com/go_map_chapter_one/

【德志大佬-設(shè)計并發(fā)安全的 map】https://halfrost.com/go_map_chapter_two/

【關(guān)于 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

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

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

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

巨人網(wǎng)絡(luò)通訊聲明:本文標題《深度解密 Go 語言中的 sync.map》,本文關(guān)鍵詞  深度,解密,語言,中的,sync.map,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《深度解密 Go 語言中的 sync.map》相關(guān)的同類信息!
  • 本頁收集關(guān)于深度解密 Go 語言中的 sync.map的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    国产高清在线观看免费不卡| 亚洲欧美日韩一区在线| h免费在线观看| 国产人妻精品久久久久野外| 一区二区三区国产精华| 亚洲四区在线观看| 国产91精品在线播放| 免费看黄裸体一级大秀欧美| 欧美日韩精品中文字幕| 99久久国产热无码精品免费| 天堂在线资源8| 日韩国产欧美一区二区| 成人免费a视频| 亚洲欧美另类日韩| 精品无码人妻一区二区三区| 涩爱av色老久久精品偷偷鲁| 91插插插插插插| 日本黄色一区| 成人福利视频在线看| 日韩a∨精品日韩在线观看| 亚洲欧美区自拍先锋| 成人国产精品免费视频| 久久久久狠狠高潮亚洲精品| 麻豆视频在线观看免费网站黄| 五月激情在线| 日本久久久久亚洲中字幕| 国内精品国语自产拍在线观看| 久久久久久久久久久久久久久久久久av| 成人丝袜高跟foot| 中文字幕人妻互换av久久| 9色精品在线| 国产精品毛片| 日韩在线 中文字幕| 国产欧美日韩精品a在线观看| 亚洲 欧美 激情 另类| 成人性免费视频| 亚洲一区二区欧美激情| 国产一区二区三区视频免费| 国产成人av片| 精品少妇人妻av免费久久洗澡| 国内精品免费一区二区三区| av一区二区三区四区| 欧洲第一无人区观看| 免费在线观看av网址| 欧美一区二区三区在线电影| 国产精品bbw一区二区三区| 国产精品天美传媒入口| 欧美xxxx黑人又粗又长| 日韩av影视大全| 在线观看91久久久久久| 国产精品理论片在线观看| 在线欧美日韩国产| 最新亚洲精品| 国产三级视频| 国产精品自拍视频在线| 亚洲欧美日韩中文在线制服| 91亚洲精品一区| 大桥未久恸哭の女教师| 在线成人高清不卡| 国产亚洲综合av| 成人深夜直播免费观看| 婷婷在线播放| 性色av蜜臀av色欲av| 色吊丝av中文字幕| 人妻少妇一区二区三区| 亚洲成色999久久网站| 欧美色视频在线观看| 黄色一级片免费播放| 免费网站在线高清观看| 国产视频123区| 一区在线观看免费| 久草福利资源在线观看| 8x8x拔插拔插影库永久免费| 国内一区二区在线| 9999精品免费视频| 欧美羞羞视频| 精品伦一区二区三区| 免费不卡欧美自拍视频| 午夜影院免费| 天天做天天躁天天躁| 欧美zozozo| 亚洲免费一在线| 国产精品久久久久9999赢消| 岛国在线免费| 色综合97天天综合网| 99久久免费看精品国产一区| 黄色免费在线观看| 亚洲成人日韩| 亚洲成人免费看| 天堂网av2014| 日韩福利一区二区三区| 中文字幕精品影院| 午夜欧美性电影| 青青青免费视频在线2| 一级日本黄色片| 96日本xxxxxⅹxxx17| 欧美国产另类| 国产精品三级在线| 亚洲男帅同性gay1069| 午夜影院在线看| 亚洲国产综合在线看不卡| 国产一区二区导航在线播放| 卡一精品卡二卡三网站乱码| 日韩在线观看免费网站| 美女看a上一区| 国产精品免费看久久久无码| 久久久久久久久久久久久久av| 男女视频免费看| 欧美成人se01短视频在线看| ririsao中文字幕免费| 国产精品18毛片一区二区| 欧美色18zzzzxxxxx| 国产精品无码自拍| 欧美黑人性受xxxx喷水| 国产成人午夜精品影院观看视频| 国产香蕉一区二区三区在线视频| 欧美激情精品久久久久久黑人| 丁香六月激情婷婷| 在线视频观看你懂的| 亚洲福利一区二区三区| 国产精品无码在线播放| 91久久久久久久久| eeuss影院www在线| 亚洲 日本 欧美 中文幕| 国产精品亚洲综合在线观看| 在线观看91精品国产入口| 天天看天天摸天天操| 欧美人与性动xxxx| 日韩国产一区三区| 国产一区二区三区美女秒播| 最近最新中文字幕在线| √天堂8资源中文在线| 秋霞在线午夜| 美国av一区二区三区| 秋霞电影一区二区| av中文一区| 中文字幕欧美一区| 午夜视频你懂的| 在线日韩视频| 国产精品一区二区精品视频观看| 欧美xxxx在线| 污污软件在线观看| 亚洲一区二区三区久久| 亚洲国产另类av| 欧美日韩爆操| 色哟哟视频在线| 热99久久精品| 亚洲一区二区三区精品在线观看| 91福利视频网站| 孩娇小videos精品| 在线国产精品播放| 欧美成人一区二区| 午夜免费福利影院| 久久人妻无码一区二区| 国产免费黄网站| 久久久久久五月天久久久久久久久| 日韩脚交footjobhd| 免费网站你懂的| 免费网站观看www在线观看| 日本韩国欧美三级| 久久av影院| 妺妺窝人体色www看人体| 在线观看视频污| 国产亚洲va综合人人澡精品| 蜜桃视频在线观看免费视频网站www| 亚洲人在线观看视频| 久久免费视频6| 国产成人黄色av| 久久久久久a亚洲欧洲aⅴ| 国产精品欧美日韩一区| 免费观看a视频| 欧美高清视频在线观看| 国产精品成人国产乱| 亚洲国产精品精华素| 香蕉视频久久久| 三级在线观看一区二区| 久久最新视频| 日本1级在线| 亚洲欧洲日产国码无码久久99| 亚洲免费毛片| 精品国产乱码一区二区三区四区| 大桥未久在线播放| 99精品国产高清在线观看| 超薄肉色丝袜足j调教99| 国产精品视频麻豆| 男人添女人下部视频免费| 日本一本二本在线观看| 一道在线中文一区二区三区| 欧美性猛交xxxx黑人猛交| 国产主播福利在线| 成人精品一区二区三区校园激情| 99热只有这里有精品| 国产精品国产亚洲精品看不卡| 国产成人免费av| 国产成人一二片| 在线观看国产精品入口男同| 欧美在线不卡视频| 国产美女亚洲精品7777| 亚洲美女在线视频| 国产精品久久久久久亚洲伦| 超碰在线一区二区三区| 欧美日韩国产首页| 久久精品一本久久99精品| 四虎国产成人永久精品免费| 中文字幕乱码人妻无码久久| 日韩电影中文 亚洲精品乱码| 豆国产97在线| 天堂av在线电影| 天天看片中文字幕| 中文不卡在线| 国产区一区二区| 国产综合av一区二区三区| 亚洲永久精品大片| 国产伦精品一区二区三区四区免费| 久久伊人精品天天| 亚洲淫性视频| 日韩视频一区在线观看| 国产精品不卡一区二区三区在线观看| 欧美视频一区二区| 人善交video高清| 九色porny自拍视频在线播放| 久99久在线| 欧美日韩精品在线观看| 操人真爽免费视频| 久久亚洲资源| 米奇777四色精品人人爽| 在线亚洲人成电影网站色www| 日韩a级作爱片一二三区免费观看| 中文字幕区一区二区三| 亚洲精品视频啊美女在线直播| 情趣视频网站在线免费观看| 国产精品白丝jk黑袜喷水| 在线免费看91| 日韩高清免费在线| 一区二区久久久| 2018日日夜夜| 国产精品丝袜一区二区| 中中文字幕av在线| 美女视频黄a视频全免费观看| 国产你懂的在线观看| 成人国产亚洲欧美成人综合网| 欧美美女黄视频| 亚洲同性gay激情无套| 亚洲桃花岛网站| 国产欧美久久久久| 啦啦啦高清在线观看www| 亚洲精品aⅴ中文字幕乱码| 欧美久久一二区| 国产精品国内免费一区二区三区| 水蜜桃一区二区三区| 日韩av最新在线观看| 91探花在线观看| 波多野结衣一区二区三区在线观看| a级黄色一级片| 久久国产一二区| 天天综合成人网| 性欧美videoshd高清| 亚洲成人日韩在线| 亚洲男人第一av网站| 国产情侣自拍av| 亚洲精品88| www黄色在线| 亚洲欧洲日本一区二区三区| 男人的天堂在线免费视频| 欧美孕妇毛茸茸xxxx| 日韩国产激情| 亚洲成人av观看| 亚洲影院免费观看| 日韩在线播放一区| 亚洲高清电影| 99久久99久久精品免费看小说.| 26uuu亚洲| 国产在线视频一区二区三区| 九九精品视频在线观看| 久久久xxx| 国产youjizz在线| 日本成人三级电影| 精品国产福利在线| 欧美另类在线播放| 欧美三级黄美女| 丁香视频五月| 日韩精品在线播放视频| 久久久精品一区二区三区| 亚洲精品中文字幕在线播放| 国产无码精品在线播放| 久久久久久99久久久精品网站| 日韩视频在线观看一区二区三区| 亚洲成人最新网站| 亚洲欧美另类久久久精品| 国产人成一区二区三区影院| 国产精品一色哟哟哟| 女人丝袜激情亚洲| 国产综合动作在线观看| 国产精品乱子乱xxxx| 欧美日本视频在线| 91免费高清视频| 色欲久久久天天天综合网| 国产精品久久占久久| 精品人妻在线播放| 国产一在线精品一区在线观看| 91在线播放国产| 国产乱人乱偷精品视频| 国内精品自线一区二区三区视频| 美女91精品| 日本精品入口免费视频| 精品写真视频在线观看| 国产丝袜精品视频| 欧美一级片网址| 久88久久88久久久| 国产伦精品一区二区三区四区视频| www久久精品| 国产a级毛片一区| 2019年中文字幕| 欧美+日本+国产+在线a∨观看| 国产综合久久| 秋霞a级毛片在线看| 国产精品麻豆久久久| 国产一级二级视频| 老熟妇一区二区三区| 亚洲中文字幕无码爆乳av| 欧美黑人疯狂性受xxxxx野外| 伦理电影国产精品| 丰满少妇在线观看| 日韩不卡高清| 一本色道久久综合狠狠躁的推荐| 亚洲涩涩av| 在线国产1区| 欧美刺激脚交jootjob|