国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

Go 每日一庫之 tunny

共 18189字,需瀏覽 37分鐘

 ·

2021-07-13 22:19

簡介

之前寫過一篇文章介紹了ants這個 goroutine 池實現(xiàn)。當時在網(wǎng)上查看相關(guān)資料的時候,發(fā)現(xiàn)了另外一個實現(xiàn)tunny。趁著時間相近,正好研究一番。也好比較一下這兩個庫。那就讓我們開始吧。

快速開始

本文代碼使用 Go Modules。

創(chuàng)建目錄并初始化:

$ mkdir tunny && cd tunny
$ go mod init github.com/darjun/go-daily-lib/tunny

使用go get從 GitHub 獲取tunny庫:

$ go get -u github.com/Jeffail/tunny

為了方便地和ants做一個對比,我們將ants中的示例重新用tunny實現(xiàn)一遍:還是那個分段求和的例子:

const (
  DataSize    = 10000
  DataPerTask = 100
)

func main() {
  numCPUs := runtime.NumCPU()
  p := tunny.NewFunc(numCPUs, func(payload interface{}) interface{} {
    var sum int
    for _, n := range payload.([]int) {
      sum += n
    }
    return sum
  })
  defer p.Close()
  // ...
}

使用也非常簡單,首先創(chuàng)建一個Pool,這里使用tunny.NewFunc()。

第一個參數(shù)為池子大小,即同時有多少個 worker (也即 goroutine)在工作,這里設(shè)置成邏輯 CPU 個數(shù),對于 CPU 密集型任務(wù),這個值設(shè)置太大無意義,反而有可能導致 goroutine 切換頻繁而降低性能。

第二個參數(shù)傳入一個func(interface{})interface{}的參數(shù)作為任務(wù)處理函數(shù)。后續(xù)傳入數(shù)據(jù)就會調(diào)用這個函數(shù)處理。

池子使用完需要關(guān)閉,這里使用defer p.Close()在程序退出前關(guān)閉。

然后,生成測試數(shù)據(jù),還是 10000 個隨機數(shù),分成 100 組:

nums := make([]int, DataSize)
for i := range nums {
  nums[i] = rand.Intn(1000)
}

處理每組數(shù)據(jù):

var wg sync.WaitGroup
wg.Add(DataSize / DataPerTask)
partialSums := make([]int, DataSize/DataPerTask)
for i := 0; i < DataSize/DataPerTask; i++ {
  go func(i int) {
    partialSums[i] = p.Process(nums[i*DataPerTask : (i+1)*DataPerTask]).(int)
    wg.Done()
  }(i)
}

wg.Wait()

調(diào)用p.Process()方法,傳入任務(wù)數(shù)據(jù),池子中會選擇空閑的 goroutine 來處理這個數(shù)據(jù)。由于我們上面設(shè)置了處理函數(shù),goroutine 會直接調(diào)用該函數(shù),將這個切片作為參數(shù)傳入。

tunnyants不同的是,tunny的任務(wù)處理是同步的,即調(diào)用p.Process()方法之后,當前 goroutine 會掛起,直到任務(wù)處理完成之后才會被喚醒。由于是同步的,所以p.Process()方法可以直接返回處理結(jié)果。這也是上面程序在分發(fā)任務(wù)的時候,啟動多個 goroutine 的原因。如果不是每個任務(wù)都啟動一個 goroutine,p.Process()方法會一直等待任務(wù)完成,那么后面的任務(wù)要等到前面的任務(wù)全部執(zhí)行完之后才能執(zhí)行。這樣就發(fā)揮不了并發(fā)的優(yōu)勢了。

這里注意一個小細節(jié),我將for循環(huán)變量作為參數(shù)傳給 goroutine 函數(shù)了。如果不這樣做,所有 goroutine 都共用外層的i,而且 goroutine 開始運行時,for循環(huán)大概率已經(jīng)結(jié)束了,這時i = DataSize/DataPerTask,索引nums[i*DataPerTask : (i+1)*DataPerTask]會越界觸發(fā) panic。

最后統(tǒng)計數(shù)據(jù),驗證結(jié)果:

var sum int
for _, s := range partialSums {
  sum += s
}

var expect int
for _, num := range nums {
  expect += num
}
fmt.Printf("finish all tasks, result is %d expect:%d\n", sum, expect)

運行:

$ go run main.go
finish all tasks, result is 5010172 expect:5010172

超時

默認情況下,p.Process()會一直阻塞直到任務(wù)完成,即使當前沒有空閑 worker 也會阻塞。我們也可以使用帶超時的Process()方法:ProcessTimed()。傳入一個超時時間間隔,如果超過這個時間還沒有空閑 worker,或者任務(wù)還沒有處理完成,就會終止,并返回一個錯誤。

超時有 2 種情況:

  • 等不到空閑的 worker:所有 worker 一直處理繁忙狀態(tài),正在處理的任務(wù)比較耗時,無法短時間內(nèi)完成;
  • 任務(wù)本身比較耗時。

下面我們編寫一個計算斐波那契的函數(shù),使用遞歸這種低效的實現(xiàn)方法:

func fib(n int) int {
  if n <= 1 {
    return 1
  }

  return fib(n-1) + fib(n-2)
}

我們先看任務(wù)比較耗時的情況,創(chuàng)建Pool對象。為了觀察更明顯,在處理函數(shù)中添加了time.Sleep()語句:

p := tunny.NewFunc(numCPUs, func(payload interface{}) interface{} {
  n := payload.(int)
  result := fib(n)
  time.Sleep(5 * time.Second)
  return result
})
defer p.Close()

生成與池容量相等的任務(wù)數(shù),調(diào)用p.ProcessTimed()方法,設(shè)置超時為 1s:

var wg sync.WaitGroup
wg.Add(numCPUs)
for i := 0; i < numCPUs; i++ {
  go func(i int) {
    n := rand.Intn(30)
    result, err := p.ProcessTimed(n, time.Second)
    nowStr := time.Now().Format("2006-01-02 15:04:05")
    if err != nil {
      fmt.Printf("[%s]task(%d) failed:%v\n", nowStr, i, err)
    } else {
      fmt.Printf("[%s]fib(%d) = %d\n", nowStr, n, result)
    }
    wg.Done()
  }(i)
}

wg.Wait()

因為處理函數(shù)中 sleep 5s,所以任務(wù)在執(zhí)行過程中就超時了。運行:

$ go run main.go 
[2021-06-10 16:36:26]task(7) failed:job request timed out
[2021-06-10 16:36:26]task(4) failed:job request timed out
[2021-06-10 16:36:26]task(1) failed:job request timed out
[2021-06-10 16:36:26]task(6) failed:job request timed out
[2021-06-10 16:36:26]task(5) failed:job request timed out
[2021-06-10 16:36:26]task(0) failed:job request timed out
[2021-06-10 16:36:26]task(3) failed:job request timed out
[2021-06-10 16:36:26]task(2) failed:job request timed out

都在同一秒中超時。

我們將任務(wù)數(shù)量翻倍,再將處理函數(shù)中的 sleep 改為 990ms,保證前一批任務(wù)能順利完成,后續(xù)任務(wù)或者由于等不到空閑 worker,或者由于執(zhí)行時間過長而超時返回。運行:

$ go run main.go
[2021-06-10 16:42:46]fib(11) = 144
[2021-06-10 16:42:46]fib(25) = 121393
[2021-06-10 16:42:46]fib(27) = 317811
[2021-06-10 16:42:46]fib(1) = 1
[2021-06-10 16:42:46]fib(18) = 4181
[2021-06-10 16:42:46]fib(29) = 832040
[2021-06-10 16:42:46]fib(17) = 2584
[2021-06-10 16:42:46]fib(20) = 10946
[2021-06-10 16:42:46]task(5) failed:job request timed out
[2021-06-10 16:42:46]task(14) failed:job request timed out
[2021-06-10 16:42:46]task(8) failed:job request timed out
[2021-06-10 16:42:46]task(7) failed:job request timed out
[2021-06-10 16:42:46]task(13) failed:job request timed out
[2021-06-10 16:42:46]task(12) failed:job request timed out
[2021-06-10 16:42:46]task(11) failed:job request timed out
[2021-06-10 16:42:46]task(6) failed:job request timed out

context

context 是協(xié)調(diào) goroutine 的工具。tunny支持帶context.Context參數(shù)的方法:ProcessCtx()。當前 context 狀態(tài)變?yōu)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Done之后,任務(wù)也會停止執(zhí)行。context 會由于超時、取消等原因切換為Done狀態(tài)。還是拿上面的例子:

go func(i int) {
  n := rand.Intn(30)
  ctx, cancel := context.WithCancel(context.Background())
  if i%2 == 0 {
    go func() {
      time.Sleep(500 * time.Millisecond)
      cancel()
    }()
  }

  result, err := p.ProcessCtx(ctx, n)
  if err != nil {
     fmt.Printf("task(%d) failed:%v\n", i, err)
  } else {
     fmt.Printf("fib(%d) = %d\n", n, result)
  }
  wg.Done()
}(i)

其他代碼都一樣,我們調(diào)用p.ProcessCtx()方法來執(zhí)行任務(wù)。參數(shù)是一個可取消的Context。對于序號為偶數(shù)的任務(wù),我們啟動一個 goroutine 在 500ms 之后cancel()掉這個Context。代碼運行結(jié)果如下:

$ go run main.go
task(4) failed:context canceled
task(6) failed:context canceled
task(0) failed:context canceled
task(2) failed:context canceled
fib(27) = 317811
fib(25) = 121393
fib(1) = 1
fib(18) = 4181

我們看到偶數(shù)序號的任務(wù)都被取消了。

源碼

tunny的源碼更少,除去測試代碼和注釋,連 500 行都不到。那么就一起來看一下吧。Pool結(jié)構(gòu)如下:

// src/github.com/Jeffail/tunny.go
type Pool struct {
  queuedJobs int64

  ctor    func() Worker
  workers []*workerWrapper
  reqChan chan workRequest

  workerMut sync.Mutex
}

Pool結(jié)構(gòu)中有一個ctor字段,這是一個函數(shù)對象,用于返回一個實現(xiàn)Worker接口的值:

type Worker interface {
  Process(interface{}) interface{}
  BlockUntilReady()
  Interrupt()
  Terminate()
}

這個接口不同的方法在任務(wù)執(zhí)行的不同階段調(diào)用。最重要的當屬Process(interface{}) interface{}方法了。這個就是執(zhí)行任務(wù)的函數(shù)。tunny提供New()方法創(chuàng)建Pool對象,這個方法需要我們自己構(gòu)造ctor函數(shù)對象,使用多有不便。tunny提供了另外兩個默認實現(xiàn)closureWorkercallbackWorker

type closureWorker struct {
  processor func(interface{}) interface{}
}

func (w *closureWorker) Process(payload interface{}) interface{} {
  return w.processor(payload)
}

func (w *closureWorker) BlockUntilReady() {}
func (w *closureWorker) Interrupt()       {}
func (w *closureWorker) Terminate()       {}

type callbackWorker struct{}

func (w *callbackWorker) Process(payload interface{}) interface{} {
  f, ok := payload.(func())
  if !ok {
    return ErrJobNotFunc
  }
  f()
  return nil
}

func (w *callbackWorker) BlockUntilReady() {}
func (w *callbackWorker) Interrupt()       {}
func (w *callbackWorker) Terminate()       {}

tunny.NewFunc()方法使用的就是closureWorker

func NewFunc(n int, f func(interface{}) interface{}) *Pool {
  return New(n, func() Worker {
    return &closureWorker{
      processor: f,
    }
  })
}

創(chuàng)建的closureWorker直接將參數(shù)f作為任務(wù)處理函數(shù)。

tunny.NewCallback()方法使用callbackWorker

func NewCallback(n int) *Pool {
  return New(n, func() Worker {
    return &callbackWorker{}
  })
}

callbackWorker結(jié)構(gòu)中沒有處理函數(shù),只能給它發(fā)送無參無返回值的函數(shù)對象作為任務(wù),它的Process()方法就是執(zhí)行這個函數(shù)。

創(chuàng)建Pool對象后,都是調(diào)用它的SetSize()方法,設(shè)置 worker 數(shù)量。在這個方法中會啟動相應(yīng)數(shù)量的 goroutine:

func (p *Pool) SetSize(n int) {
  p.workerMut.Lock()
  defer p.workerMut.Unlock()

  lWorkers := len(p.workers)
  if lWorkers == n {
    return
  }

  for i := lWorkers; i < n; i++ {
    p.workers = append(p.workers, newWorkerWrapper(p.reqChan, p.ctor()))
  }

  // 停止過多的 worker
  for i := n; i < lWorkers; i++ {
    p.workers[i].stop()
  }

  // 等待 worker 停止
  for i := n; i < lWorkers; i++ {
    p.workers[i].join()
    // -----------------
  }
  p.workers = p.workers[:n]
}

SetSize()其實在擴容和縮容的時候也會調(diào)用。對于擴容,它會創(chuàng)建相應(yīng)數(shù)量的 worker。對于縮容,它會將多余的 worker 停掉。與ants不同,tunny的擴容縮容都是即時生效的。

代碼中,我用-----------------標出來的地方我覺得有點問題。對于縮容,因為底層的數(shù)組沒有變化,workers切片長度縮小之后,數(shù)組中后面的元素實際上就訪問不到了,但是數(shù)組還持有它的引用,算是一種內(nèi)存泄漏吧。所以穩(wěn)妥起見最好加上p.workers[i] = nil?

這里創(chuàng)建的 worker 實際上是包裝了一層的workerWrapper結(jié)構(gòu):

// src/github.com/Jeffail/worker.go
type workerWrapper struct {
  worker        Worker
  interruptChan chan struct{}
  reqChan chan<- workRequest
  closeChan chan struct{}
  closedChan chan struct{}
}

func newWorkerWrapper(
  reqChan chan<- workRequest,
  worker Worker,
)
 *workerWrapper
 {
  w := workerWrapper{
    worker:        worker,
    interruptChan: make(chan struct{}),
    reqChan:       reqChan,
    closeChan:     make(chan struct{}),
    closedChan:    make(chan struct{}),
  }

  go w.run()
  return &w
}

workerWrapper結(jié)構(gòu)創(chuàng)建之后會立刻調(diào)用run()方法啟動一個 goroutine:

func (w *workerWrapper) run() {
  jobChan, retChan := make(chan interface{}), make(chan interface{})
  defer func() {
    w.worker.Terminate()
    close(retChan)
    close(w.closedChan)
  }()

  for {
    w.worker.BlockUntilReady()
    select {
    case w.reqChan <- workRequest{
      jobChan:       jobChan,
      retChan:       retChan,
      interruptFunc: w.interrupt,
    }:
      select {
      case payload := <-jobChan:
        result := w.worker.Process(payload)
        select {
        case retChan <- result:
        case <-w.interruptChan:
          w.interruptChan = make(chan struct{})
        }
      case _, _ = <-w.interruptChan:
        w.interruptChan = make(chan struct{})
      }
    case <-w.closeChan:
      return
    }
  }
}

每個 worker goroutine 都在嘗試向w.reqChan通道中發(fā)送一個workRequest結(jié)構(gòu)數(shù)據(jù),發(fā)送成功之后,從jobChan中獲取任務(wù)數(shù)據(jù),然后調(diào)用Worker.Process()方法執(zhí)行任務(wù),最后將結(jié)果發(fā)送到retChan通道中。這里其實有好幾個交互。需要結(jié)合Process()方法來看才更清晰:

func (p *Pool) Process(payload interface{}) interface{} {
  request, open := <-p.reqChan
  request.jobChan <- payload
  payload, open = <-request.retChan
  return payload
}

刪掉無相關(guān)的代碼,最后就是上面這樣。我們在調(diào)用池對象的Process()方法時,嘗試從通道reqChan中接收數(shù)據(jù),然后將任務(wù)數(shù)據(jù)發(fā)送到jobChan通道中,最后從retChan通道中接收結(jié)果。與上面的run流程結(jié)合來看,實際上在正常執(zhí)行一個任務(wù)時,PoolworkerWrapper有 3 次交互。

觀察Pool創(chuàng)建到workerWrapper創(chuàng)建的流程,我們可以看到實際上Pool結(jié)構(gòu)中的reqChanworkerWrapper結(jié)構(gòu)中的reqChan是同一個通道。即workerWrapper啟動后,會阻塞在向reqChan通道發(fā)送數(shù)據(jù)上,直到調(diào)用了PoolProcess*()方法,從通道reqChan取出數(shù)據(jù)。Process()方法得到workRequest會向它的jobChan通道中發(fā)送任務(wù)數(shù)據(jù)。而workerWrapper.run()方法成功發(fā)送數(shù)據(jù)到reqChan之后就開始等待從jobChan通道中接收數(shù)據(jù),這時接收到Process()方法發(fā)送過來的數(shù)據(jù)。開始執(zhí)行w.worker.Process()方法,然后向retChan通道發(fā)送結(jié)果數(shù)據(jù),Process()方法在成功發(fā)送數(shù)據(jù)到jobChan之后,就開始等待從retChan通道中接收數(shù)據(jù)。接收成功之后,Process()方法返回,workerWrapper.run()繼續(xù)阻塞在w.reqChan <-這條語句上,等待處理下一個任務(wù)。注意jobChanretChan都是workerWrapper.run()方法中創(chuàng)建的通道。

那么超時是怎么實現(xiàn)的呢?看方法ProcessTimed()的實現(xiàn):

func (p *Pool) ProcessTimed(
  payload interface{},
  timeout time.Duration,
)
 (interface{}, error)
 {
  tout := time.NewTimer(timeout)
  var request workRequest
  select {
  case request, open = <-p.reqChan:
  case <-tout.C:
    return nil, ErrJobTimedOut
  }

  select {
  case request.jobChan <- payload:
  case <-tout.C:
    request.interruptFunc()
    return nil, ErrJobTimedOut
  }

  select {
  case payload, open = <-request.retChan:
  case <-tout.C:
    request.interruptFunc()
    return nil, ErrJobTimedOut
  }

  tout.Stop()
  return payload, nil
}

同樣地,刪除不相干的代碼。首先,創(chuàng)建一個timer,超時時間由傳入?yún)?shù)指定。后面有 3 個select語句:

  • 等待從p.reqChan取數(shù)據(jù),即等待有 worker 空閑;
  • 等待發(fā)送數(shù)據(jù)到jobChan,即等待 worker 從jobChan取出任務(wù)數(shù)據(jù);
  • 等待從retChan取數(shù)據(jù),即等待 worker 將結(jié)果發(fā)送到retChan

第一種情況,如果超時了,說明 worker 都處于繁忙狀態(tài),直接返回任務(wù)超時。后面兩種情況實際上是任務(wù)已經(jīng)開始執(zhí)行了,但是在規(guī)定的時間內(nèi)沒有完成。這兩種情況,需要終止任務(wù)的執(zhí)行。我們看到上面調(diào)用了workerRequest.interruptFunc()方法,也就是workerWrapper.interrupt()方法:

func (w *workerWrapper) interrupt() {
  close(w.interruptChan)
  w.worker.Interrupt()
}

這個方法就是簡單關(guān)閉了interrupteChan通道,然后調(diào)用worker對象的Interrupt()方法,默認實現(xiàn)中這個方法都是空的。

interruptChan通道關(guān)閉后,goroutine 中等待從jobChan接收數(shù)據(jù)和等待向retChan發(fā)送數(shù)據(jù)的操作都會取消:

select {
case payload := <-jobChan:
  result := w.worker.Process(payload)
  select {
  case retChan <- result:
  case <-w.interruptChan:
    w.interruptChan = make(chan struct{})
  }
case _, _ = <-w.interruptChan:
  w.interruptChan = make(chan struct{})
}

ProcessCtx()實現(xiàn)也是類似的。

最后調(diào)用workerWrapper.stop()會關(guān)閉closeChan通道,這會導致workerWrapper.run()方法中的for循環(huán)跳出,進而執(zhí)行defer函數(shù)中的close(retChan)close(closedChan)

defer func() {
  w.worker.Terminate()
  close(retChan)
  close(w.closedChan)
}()

這里需要關(guān)閉retChan通道是為了防止Process*()方法在等待retChan數(shù)據(jù)。

closedChan通道關(guān)閉后,workerWrapper.join()方法就返回了。

func (w *workerWrapper) join() {
  <-w.closedChan
}

Worker幾個方法的調(diào)用時機:

  • Process():執(zhí)行任務(wù)時;
  • Interrupt():任務(wù)因為超時會被 context 取消時;
  • BlockUntilReady():每次執(zhí)行新任務(wù)前,可能需要準備一些資源;
  • Terminate()workerWrapper.run()中的 defer 函數(shù)中,即停止 worker 后。

這些時機在代碼中都能清晰地看到。

基于源碼,我畫了一個流程圖:

圖中省略了中斷的流程。

tunny vs ants

tunny設(shè)計的思路與ants有較大的區(qū)別:

tunny只支持同步的方式執(zhí)行任務(wù),雖然任務(wù)在另一個 goroutine 執(zhí)行,但是提交任務(wù)的 goroutine 必須等待結(jié)果返回或超時。不能做其他事情。正是由于這一點,導致tunny的設(shè)計稍微一點復雜,而且為了支持超時和取消,設(shè)計了多個通道用于和執(zhí)行任務(wù)的 goroutine 通信。一次任務(wù)執(zhí)行的過程涉及多次通信,性能是有損失的。從另一方面說,同步的編程方式更符合人類的直覺。

ants完全是異步的任務(wù)執(zhí)行流程,相比tunny性能是稍高一些的。但是也因為它的異步特性,導致沒有任務(wù)超時、取消這些機制。而且如果需要收集結(jié)果,必須要自己編寫額外的代碼。

總結(jié)

本文介紹了另一個 goroutine 池的實現(xiàn)tunny。它以同步的方式來處理任務(wù),編寫代碼更加直觀,對任務(wù)的執(zhí)行流程有更強的控制,如超時、取消等。當然實現(xiàn)也復雜一些。tunny代碼不走 500 行,非常建議讀一讀。

大家如果發(fā)現(xiàn)好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue??

參考

  1. tunny GitHub:https://github.com/Jeffail/tunny
  2. ants GitHub:github.com/panjf2000/ants
  3. Go 每日一庫 GitHub:https://github.com/darjun/go-daily-lib


推薦閱讀


福利

我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關(guān)注公眾號 「polarisxu」,回復 ebook 獲??;還可以回復「進群」,和數(shù)萬 Gopher 交流學習。

瀏覽 41
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 国产美女精品| 欧美午夜精品久久久久免费视| AV解说| 天天操综合| 九九精品视频在线观看| HEYZO少婦AV無碼精品| AV资源在线免费观看| 91久久精品国产91久久公交车| 亚洲无码影视| 江苏妇搡BBBB搡BBB| 免费无码国产| 亚洲国产成人91PORN| 亚洲婷婷五月天| 污视频网站免费在线观看| 色久影院| 国产一级性爱视频| 国产精品视频一区二区三| 国产中文在线| 18一20女一片毛片| 国产一级a毛一级a毛观看视频网站| 欧美一级特黄AAAAAA片| 99热免费精品| 91ccc| 一级片操逼| 人人爱人人爽人人操| 日本一级特黄电影| 无码一区二区三区四区五区| 日韩高清不卡| 亚洲h| 一本一道无码免费看视频| 亚洲黄色成人| 超碰婷婷| 人人做人人做人人做,人人做全句下一 | 国产A级视频| 人人干超碰| 超碰永久| 欧美日韩一区二区三区四区五区六区| 久久99久久视频| 亚洲福利视频97| 欧美成人综合| 看毛片的网站| 亚洲精品蜜桃| 残忍另类BBWBBWBBW| 视频在线观看一区| 欧美日韩国产在线播放| 一级Aa视频免费看| 91精品在线观看视频| 3D动漫精品一区二区在线播放免费| 欧美污视频在线观看| 天堂AV无码AV| 人妻一区二区在线| 在线A片免费观看| 亚洲视频1区| AV无码毛片| 狠狠狠久久久| 欧美在线成人网| www一个人免费观看视频www| 日日夜夜精品| 国产一级一片免费播放放a| 97毛片| 美女被操免费网站| 国产乱婬AAAA片视频| 久久99深爱久久99精品| 大鸡吧网站| 在线你懂| www.狠狠| 色综合久久88色综合天天| 最近中文字幕免费MV第一季歌词怀孕 | 亚洲无码激情| 国产午夜福利视频| 伊人干综合| 亚洲久热| 伊人中文字幕| 91精品又粗又猛又爽| 山东熟妇搡BBBB搡BBBB| 丁香五月激情综合| 天天拍天天干| 在线观看中文字幕| 国产精品久久久| 国产免费AV网站| 久激情内射婷内射蜜桃欧美一级| Av黄色| 欧美老女人操逼视频| 激情av在线观看| 中文字幕在线观看1| 欧美黄色激情视频网站| 亚洲国产黄片| 中文字幕在线播放AV| 日本成人激情视频| 午夜免费AV| 青青草国产在线视频| 国产婷婷五月| 欧美日韩免费观看视频| 少妇搡BBBB搡BBB搡18禁| 人人舔人人爱| 欧美色图俺去了| 色五月欧美| 亚洲AV成人一区二区三区不卡| 中文字幕亚洲天堂| 欧美熟妇一区二区三区| 欧美日韩中文字幕在线视频 | 天天撸天天干| 欧美成人色图| 日韩一级二级| 国产色五月视频| 天天插在线视频| 特级毛片AAAAAA蜜桃| 四虎在线观看视频| 亚洲二区无码| 先锋成人电影| 国产A级毛片久久久久久| 性欧美欧美巨大69| 牛牛AV在线| 99久久久国产| 一道本一区二区三区| 精品成人无码| 午夜精品18视频国产17c| 性爱视频网站| 亚洲高清视频在线观看| 无码免费一区二区三区| 蜜桃影视| 超碰人人干人人操| 日本有码中文字幕| 无码电影免费观看| 在线免费观看无码视频| 黄色AV网| 国产精品视频久久久| 中文字幕不卡在线观看| 亚洲va| 久操视频在线| 无码成人在线观看| 一卡二卡在线视频| 欧美插菊花综合网| 亚洲无码精品一区二区三区| 黄页免费视频| 口爆吞精在线观看| 免费看一级无码成人片| 欧美一级A片高清免费播放| 不卡无码中文字幕一区| 中文无码日本高潮喷水| 波多野结衣av一区| 福利一区在线观看| 色婷婷国产精品综合在线观看| 豆花视频成人版www满18| 亚洲有码在线播放| 久久免费观看视频| 成人国产精品秘在线看| 亚洲va欧美va天堂v国产综合| 成人a电影| 污视频网站免费在线观看| 欧一美一婬一伦一区二区三区黑人-亚 | 热逼视频| 大香焦草久| 欧美AAAAA| 国产精品久久久久久久牛牛| 欧美精品成人免费| 亚洲欧美日韩电影| 成人日韩无码| 色欲国产精品欧美在线密| 最新中文字幕在线播放| 视频一区中文字幕| 视色视频在线观看18| 中文有码视频| 国产性爱av| 欧美黄色小说| 日本三级片免费| 五月天婷婷在线视频| www高清无码| 青娱乐伊人| 天天干天天拍| 亚洲中文字幕在线播放| 一本免费视频| 欧美日韩第一区| 久久草在线播放| 色欲亚洲| 精品无码视频| 国产精品一级二级三级| 超碰综合| 日本中文字幕不卡| 日本不卡中文字幕| 大香蕉97| 欧美A片在线免费观看| 丁香五月婷婷基地| 家庭乱伦av| 91精品人妻一区二| 中文字幕第一页在线| 精品69| 最新中文字幕777私人在线| 777免费观看成人电影视频| 爽爽午国产浪潮AV性色www| 久久国产亚洲| 无码黄片免费| 亚洲精品黄色| 一本色道精品久久一区二区三区 | 亚洲色激情| 天天撸在线| 国产中文在线观看| 青青伊人网| 日韩一欧美| 玖玖婷婷| 蜜桃91精品入口| 日本激情网站| 中文字幕久久播放| 操逼网123首页| yjizz视频| 俺去听听婷婷| 亚洲色图15p| 亚洲三级无码在线观看| 草榴在线视频| 色婷婷狠狠| 激情一区| 国产精品免费久久| 国产黄色视频网站在线观看| 成人网站在线观看视频| 男女日日批黄色三级| 国产丰满大乳无码免费播放| 国产传媒_色哟哟| 尤物AV| 精品乱码一区| 免费电影日本黄色| 天天视频黄色| 99re在线观看| 夜夜夜操操操| 天天射天天操天天干| 久草美女| 91蝌蚪久久| 久久久极品| 国产成人视频免费| 欧美亚韩一区二区三区| 国产久久视频在线观看| 俺也来www俺也色com| 麻豆国产一区二区三区四区| 淫荡少妇美红久久久久久久久久| 超碰人人爱人人操| 群交无码| 国产乱子伦真实精品| 日韩AV电影网| 可以免费看的AV| 91大鸡巴| 2019狠狠操| 欧美福利在线观看| 国产欧美一区二区三区四区| 懂色av一区蜜桃| 青青草原国产视频| 丁香五月激情小说| 国产福利视频| 福利在线看| 成人做爰100片免费观看视频 | AV在线免费播放| 香蕉国产精品| 黄片视频国产| 久久黄色视频网站| 国产精品操逼网站| 欧美aaa视频| 亚洲日韩中文字幕| 亚洲中文字幕免费观看视频| 三级片一区| 国内特级毛片| 91一级A片在线观看| 激情五月天导航| 日日碰狠狠| av天天操| 国产高清色| 亚洲综合婷婷| 91嫖妓站街埯店老熟女| 天天日天天添| 亚洲色图狠狠撸| 成人777777免费视频色| 一级欧美视频| 老湿机91| 日韩亚洲在线观看| 日韩人妻无码一区二区三区99| 一级黄色影院| 综合婷婷久久| av无码在线观看| 欧一美一婬一伦一区?| 91在线无码精品秘国产| 国产激倩都市一区二区三区欧美| 人人艹在线| 在线免费观看毛片| 日韩无码91| 超碰97av| 伊人免费| 丰满熟妇高潮呻吟无码| 麻豆视频在线| 国产精品一级二级三级| 精东影业AV无码精品| 综合网亚洲| 91人妻人人澡人人爽人人DVD| AV东方在线| 国产精品HongKong麻豆| 狼友自拍| 強姦婬片A片AAA毛片Mⅴ| 欧美午夜精品久久久久免费视| 嫩BBB槡BBBB槡BBBB视频-百度| 中文字幕++中文字幕明步| 爱就色色网| 伊人自拍| 99精品国产一区二区| 91网站免费在线观看| 日本在线一级片| 18禁污网站| 青草久久久| 欧美精品久久久久久久久| 黑人无码AV黑人天堂无码AV| 麻豆视频在线看| 性无码一区二区三区在线观看 | 强开小嫩苞毛片一二三区| 安徽妇搡BBBB搡BBBB袄爱直播| 国产福利视频| 91成人网站| 国产视频久久久| 五月天无码免费视频| 西西444WWW无码大胆| 国产精品夜夜爽3000| 亚洲a级| 日本人人操人人摸| 欧美黄色精品| 欧美成人毛片AAAAAA| 波多野结衣国产区42部| 久久这里| 三级视频国产| 狠狠干2018| 亚洲欧洲精品成人久久曰影片| 黄色成人网站在线观看免费| JlZZJLZZJlZZ亚洲女人17| 亚洲天堂视频在线观看免费| 亚洲欧美日韩黑料吃瓜在线观看| wwwAV在线观看| 五月丁香六月| 天天撸在线| 口爆在线| 亚洲一区久久| 影音先锋成人AV| 国产1级a毛a毛1级a毛1级| 国产精品秘久久久久久99| 精品一区二区三区无码| 青青草精品视频| 97精品人妻一区二区三区香蕉农| 爱爱黄色视频| 手机看片1024久久| 麻豆国产精品| 山东乱子伦视频国产| 日韩成人精品视频| 国产特级婬片免费看| 欧美一级在线视频| 在线看黄网| 国产欧美成人| 99久久综合国产精品二区| 亚洲成av人无码| 亚洲欧美在线一区| 国产精品久久久久久久久久久久久久 | 天天操夜夜干| 精品操逼| 青娱乐网站| 国内精品一区二区| 一级特黄妇女高潮AA片免费播放| 久久婷婷五月天| 艹逼视频在线观看| 午夜亚洲国产一区视频网站| 欧美午夜无码| 伊人五月婷婷| 丰满人妻一区二区| 狼人综合色| 91久久国产综合久| 五月天啪啪视频| 日韩精品成人电影| 中国精品77777777| 无码人妻一区二区三区精品不付款 | 天天日夜夜草| 午夜大黄片| 99色色网| 操逼视频91| 囯产精品久久久久久久久久| 亚洲成人av在线播放| 无码网| 国产69久久精品成人看| 色男人天堂| 日韩三级av| 败火老熟女ThePorn视频| 丝袜一区| 大学生18一19GAY169| 国产成人精品在线| 大香蕉草久| 日韩91| 亚洲中文字幕视频在线| 人妻少妇91精品一区黑人| 99久久99久久| 国产伦精品一区二区三区色大师| 久久视频免费观看| 人妻精品综合码| 成人伊人网| 在线观看免费黄色| 日本女人高潮视频| 日韩国产中文字幕| 欧美MV日韩MV国产网站| 色婷婷无码| 777超碰| 老太奶性BBwBBw侧所| 高清日韩无码视频| 欧美色图在线观看视频| 一级黄色片免费看| 成人午夜福利视频| 中文在线最新版天堂8| 亚洲综合视频在线观看| 操BBB操BBB| 在线观看中文字幕| 丁香五月五月婷婷| 成人777777| 午夜精品无码| 日韩啪啪啪网站| 全部免费黄色视频| 蜜芽成人在线| 91精品人妻一区二区三区四区| 无码三级片在线观看| 午夜成人福利剧场| 亚洲日韩一区二区三区四区 | 中文字幕色情| 国产精品色视频| 欧美一区二区三区四| 色噜噜狠狠色综无码久久合欧美| 午夜啪啪视频| 三级黄片免费看| 日韩无码性爱| 小明成人免费视频| 人妻无码A| 黄色一级a片| 五月六月丁香| 夫妻成人免费看片一区二区| 欧美成人三级在线| 免费国产黄色视频网站| 无码在线免费观看| 亚洲视频免费在线播放| 热久久最新地址| 韩国av在线| 男女视频91| 日韩激情视频在线观看| 免费小视频| 影音先锋麻豆| 91在线成人视频| 亚洲福利片| 色噜噜狠狠一区二区三区牛牛影视| 国产女同在线观看| 山东wBBBB搡wBBBB| 精品人伦一区二区三区| 十八禁网站在线观看| 婷婷三区| 自拍偷拍综合网| 久久六六| 中文字幕视频在线观看| 欧美一区二区三区免费| 婷婷五月色播| 羞羞色院91蜜桃| 人妻超碰| 婷婷精品免费| 99re视频精品| www.狠狠| 色婷婷国产精品| 特级黄色A片| 91成人在线观看学生和老师| 天堂а√在线中文在线新版| 精品国产AV无码一区二区三区| 麻豆一区二区| 加勒比精品在线| 亚洲黄色一级电影| 五月无码视频| 黄色成人在线视频| 麻豆乱伦视频| 制服.丝袜.亚洲.中文.豆花| 嫩草在线观看| 少妇视频一区| 国产色色网| 天堂网中文在线| 日韩国产AV| 青青色在线观看| 影音先锋91久久网| 菊花综合网| 五月天福利视频| 少妇高潮喷水视频| 激情五月天av| 色我影院| 国产免费一区二区| 中文字幕高清无码在线| 无码毛片在线观看| 午夜精品久久久久久久99老熟妇| 懂色av粉嫩av蜜臀av| a级片在线观看| 大香蕉第一页| 久草社区| 成人性爱免费视频| 日韩高清区| 四川揉BBB搡BBB| 午夜操一操| 午夜成人小电影| A片免费网址| 欧美成人免费精品| 日韩大香蕉| 婷婷视频在线观看| 熟女3P| 久久久久久久AV| 精品乱码一区| 黄片入口| 91免费在线看| 美女天天日| 九九伊人大香蕉| 日韩群交| 另类图片亚洲色图| 99亚洲视频| 熟女熟妇人妻一区二区三区| 亚洲北条麻妃一级A片| 大香蕉一区二区三区| 国产精品va| 亚洲先锋影音| 午夜噜噜| 亚洲一级免费免费在线观看| 69成人网站| 免费在线观看a片| 东京热久久综合| 日本大香蕉在线视频| 日韩毛片| www.51av| 无码中文字幕在线播放| 国产精品宾馆在线| 午夜理论在线| 特黄特色免费大片| 免费国产黄色| 国产内射无码| 欧美日韩性爱网站| 三级视频国产| 人人妻日日摸狠狠躁| 亚洲视频免费观看| 成人国产综合| 韩日中文字幕| 69人妻人人澡人人爽久久| 在线看的av| 午夜免费播放观看在线视频| 人妻少妇精品视频| 亚洲无aV在线中文字幕| 亚洲精品久久久久avwww潮水| 激情另类视频| 996精品在线| 成人视频三级| 鸡巴网站| 亚洲天堂一区二区| 91福利视频网站| 亚洲砖区区免费| 啊啊啊亚洲| 国产乱国产乱老熟300视频| 免费在线观看AV| 麻豆91精品人妻成人无码| 性饥渴熟妇乱子伦| 在线观看老湿视频福利| 国产欧美综合一区二区| 天天搞搞| 色色色色色色网站| 九九九免费视频| 国产成人免费在线| 中文字幕不卡视频| 欧美AⅤ在线| 成人午夜天堂| 午夜精品久久久久久久99热精东 | 亚洲无码AV片| 中文字幕在线成人| 国产suv精品一区二区6精华液| 91精品国产亚洲| 日韩经典视频在线播放| 日韩在线观看一区二区| 久久AV电影| 97人人爱| 国内精品久久久久| 日韩在线视频中文字幕| 粉嫩av在线| 日本成人一区二区三区| 国产婬片一级A片AAA毛片AⅤ| 最新中文字幕视频| 亚洲精品91| 亚洲操逼网站| 九九偷拍| 欧美八区| 色欲综合网| 人人妻人人要| 男人视频网| AV资源在线免费观看| 亚洲欧美日本在线| 小黄片高清无码| 中字一区人妻水多多| 青青草AV| 大香蕉中文在线| 在线观看黄色av| 可以免费看的av| 黄色视频小说| 国产黄色视频网站在线观看| 丁香五月激情在线| 人人摸人人看人人草| 亚洲成人在线视频免费观看| 亚州一级二级| 久久久久久久久久免费视频| 成人a级网站| 久久AV电影| 欧美在线中文字幕| 亚洲自拍偷拍视频| 国产1区2区3区| 男女做爱视频网站| 四虎成人网址| 亚洲字幕在线观看| 中文字幕无码成人| 新中文字幕| 日韩精品一区二区亚洲AV观看| 亚洲午夜福利视频在线观看| 日本一区二区三区四区在线观看 | 亚洲AV激情无码专区在线播放| 成人激情在线视频| 豆花视频成人版www满18| 内射视频在线免费观看| 校园春色亚洲无码| 91丨九色丨熟女泻火| 欧美国产第一页| 天天日av| 翔田千里无码一区| 国产无遮挡又黄又爽又色视频软件| 夜夜夜操操操| 中文字幕免费一区| 美女在线扣穴| 天天爽天天| 婷婷开心色四房播播免费| 日韩一级一片内射视频4K| 亚洲不卡| 成年人在线观看| 乱伦五月天| 超碰超碰| 天天操天天操天天操| 91热视频| 天天干天天操天天| 99香蕉视频| 久久久久久网| 无码黑人| 加勒比综合在线| 日韩欧美中文字幕在线观看| 中文字幕日韩有码| 国产女人18毛片18精品| 日本黄色免费| 精品香蕉视频| 日韩黄色小说| 操B视频网站| 亚洲免费三级片| 99色视频| 操逼视频国产| 亚洲综合日韩在线| 手机av在线| 51成人网站免费| 伊人干综合| 婷婷色图| 日本操逼网| 啪啪啪网站| 辽宁模特张雪馨视频最新| 激情男人网| 人人操碰成人网| 日韩黄色中文字幕| 99re6热在线精品视频功能| 欧美激情内射| 天堂黄片| www99| 天堂久久av| 成人三级视频在线| 美女福利导航| 国产日韩一区二区三免费高清| 欧美+日韩+国产+成人+在线 | 91吴梦梦一区二区传媒| 2022黄片| 操久| 亚洲成人综合在线| 中文字幕熟女人妻| 日日干天天| 九九九色| 成人三级电影| 日韩理论片| 国产高清做爱| 精品久久免费| 插入综合网| 揄拍成人国产精品视频| 亚洲婷婷精品国产成人| 国产精品自拍在线观看| 综合伊人大香蕉| 亚洲成人不卡| 久久一二三四| 黄色视频在线观看免费网站| 日韩精品人妻无码| 国产91在线亚洲| 久久久成人视频| 操B无码| 爱干视频| 亚洲综合伊人| 亚洲国产精品久久久久婷婷老年| 无码国产传媒精品一区| 亚洲色视频在线| 久久久久久亚洲AV黄床| 欧美色女人| 久一久久| 日韩一级片免费看| 麻豆国产91在线播放| 日本少妇网站| 色色9999| 91麻豆成人| 国产精品黄片| 九九久久国产精品| 伊人激情影院| 2021av| 国内精品久久久久久久久久变脸| 久久久久极品| 三级午夜在线无码| 欧美一级在线视频| 色婷婷大香蕉| 9999久久久久| 国产嫩草久久久一二三久久免费观看 | 手机AV免费| 午夜性爱福利视频| 国产一区二区不卡亚洲涩情| 91香蕉国产视频| 91国语又粗又大对白| 男人AV在线| 亚洲sese| 人操人| 国产十欧洲十美国+亚洲一二三区在线午夜| 99九九99九九九99九他書對| AV777777| 伊人影院99| 麻豆成人精品国产免费| 视色影院| 上床网站| 91AV在线播放| 欧美激情DVD| 欧美日韩视频免费观看| 日本亚洲国产| 日韩无码中文字幕视频| 69成人免费视频| 陈冠希和张柏芝mv| 人妻人人爽| 99re6热在线精品视频功能| 成人中文字幕无码| 欧美日韩日逼视频| 欧美精品福利| 三级无码在线| 欧美日韩国产一区二区三区| 欧美成人毛片AAAAAA| 蜜桃网站视频| 啪啪啪AV| 大香蕉综合久久| JLZZJLZZ亚洲女人| 九九热精品视频在线观看| 亚洲群交| 欧美视频综合网| 久久免费看| 日韩激情一区| 欧美午夜精品成人片在线播放| 亚洲免费性爱视频| 亚洲AV白浆| 国产精品色呦呦| 成人三级片网| 无码内射在线播放| 操逼在线免费观看| 国产高清在线视频| 91人妻人人澡人人爽人人精吕| 在线成人毛片| 亚洲中文无码电影| 开心深爱激情网| 亚洲成人av在线| 俺来也官网欧美久久精品| 成年人黄色视频免费观看| 真实白嫖91探花无码| 久久久人妻熟妇精品无码蜜桃| 欧美中文字幕在线视频| 一道本在线| 黄色视频在线| 亚洲精品一级| 久久成人电影院| 中文字幕+乱码+中文乱码www | 黄片免费播放| 国产AV一级片| 欧洲成人在线播放| 51嘿嘿嘿国产精品伦理| 五月天久久久久| 欧美成人免费网站| 狠狠躁日日躁夜夜躁A片无码视频 强伦轩一区二区三区四区播放方式 | 日韩欧美国产成人| 51妺嘿嘿午夜福利| www.色999| 久久久久中文字幕| 日本黄色视频免费| 久久久久久久久免费看无码| 美女被操网站| www99| 一级黄色视频片| 成人精品水蜜桃| 欧美成人久久| 11孩岁女精品A片BBB| 午夜激情毛片| 韩国精品在线观看| 亚洲精品资源| 欧美成人黄色小视频| 俺来也俺去www色情网| 九九综合伊人7777777| 色播婷婷五月天| 91在线免费视频| 不卡无码免费视频| 91成人视频在线免费观看| 丁香婷婷一区二区三区| 成人黄色视频网站| 免看一级a一片| 亚洲片在线观看| 伊人五月天激情| 美女一级变态毛片| 亚洲AV无码成人精品区www| 东北老女人操逼| 7799精品| 免费中文资源在线观看| 中文字幕无码一区二区三区一本久| www.婷婷色| 99热免费在线| www,操逼| 欧美性爱成人| 草b视频| 国产成人亚洲日韩| 3D精品啪啪一区二区三区| 欧美日韩人妻| 色婷婷大香蕉| 亚洲色777| 欧美日韩第一区| 国产一级a毛一级a做免费图片| 亚洲在线中文字幕| 国产精品操逼网站| 福利视频一区二区| 亚洲无码网| 狠狠躁日日躁夜夜躁A片视频| 无码在线观看免费| 日韩在线成人| 中文字幕免费在线观看| 中文字幕无码一区二区三区一本久| 久激情内射婷内射蜜桃欧美一级| 日韩一级免费视频| 欧美亚洲成人网站| 色播AV| 99久久99九九99九九九| 私人玩物』黑絲OL尤物| 久久嫩草| 国产内射无码| 黄色毛片,男人天堂| 2018天天日天天操| 色综合天天综合网国产成人网| 蜜桃一区二区视频在线观看| 日韩AV网站在线观看| 亚洲中文字幕在线视频观看| 欧美一级性爱| 西西午夜视频| 日韩在线视频一区二区三区| 东方成人AV| 视频一区在线播放| 七六十路の高齢熟妇无码| 国产精品成人AV在线| 二区三区无码| 婷婷激情av| 国产免费一区二区三区最新不卡| 欧美日韩岛国| 天天拍夜夜拍| 91人人妻| 伊人日逼| 九色自拍视频| 人人操人人色| 国产精品一区二区在线播放| 亚洲成人AV在线播放| 色我影院| 国产精品久久久久久久牛牛| 成人无码视频在线观看| 91熊猫视频| 亚洲精品一区二区三区无码电影 | 最新无码视频| 日韩精品成人AV| 五月婷婷激情五月| 国产高清不卡| 三级毛片网站| 黄色无码电影| 好吊一区二区三区| 成人精品一区二区无码| 亚洲成人网在线观看| 中文字幕一区二区蜜桃| 婷婷综合一区| 69成人精品国产| 亚洲性图第一页| 国产精品不卡在线观看| 国产午夜福利电影| 久久老女人| 影音先锋日韩| 日韩插插| 男人天堂婷婷| 欧美成人精品欧美一级乱黄| 日本久久久久| 国产一级AV国产免费| 青吴乐大香蕉| 熟妇一区二区| 国产一级18片视频| 久久久永久免费视频|