<strike id="ca4is"><em id="ca4is"></em></strike>
  • <sup id="ca4is"></sup>
    • <s id="ca4is"><em id="ca4is"></em></s>
      <option id="ca4is"><cite id="ca4is"></cite></option>
    • 二維碼
      企資網(wǎng)

      掃一掃關(guān)注

      當(dāng)前位置: 首頁 » 企資快報 » 服務(wù) » 正文

      16_毫秒的挑戰(zhàn)_圖表庫渲染優(yōu)化

      放大字體  縮小字體 發(fā)布日期:2021-09-05 11:48:21    作者:媒體小英    瀏覽次數(shù):17
      導(dǎo)讀

      宿爽 InfoQ 作者 | 宿爽整理 | 王強(qiáng)在 ApacheCon Asia 2021] 大會的“數(shù)據(jù)可視化論壇”上,Apache ECharts PMC 成員宿爽發(fā)表了題為“16 毫秒的挑戰(zhàn):圖表庫渲染優(yōu)化”的演講。本文是這次演講的內(nèi)容總結(jié)。今天我演講

      宿爽 InfoQ

      作者 | 宿爽

      整理 | 王強(qiáng)

      在 ApacheCon Asia 2021] 大會的“數(shù)據(jù)可視化論壇”上,Apache ECharts PMC 成員宿爽發(fā)表了題為“16 毫秒的挑戰(zhàn):圖表庫渲染優(yōu)化”的演講。本文是這次演講的內(nèi)容總結(jié)。

      今天我演講的主題叫做“16 毫秒挑戰(zhàn):圖表庫渲染優(yōu)化”。

      標(biāo)題里的 16 毫秒是怎么來的呢?因為 UI 系統(tǒng)最常見的刷新頻率是 60hz,也就是每一幀在約 16 毫秒內(nèi)渲染完成就會比較流暢,交互不會有卡頓感。

      后一部分叫“圖表庫渲染優(yōu)化”。圖表庫是數(shù)據(jù)可視化的領(lǐng)域,涉及很豐富的呈現(xiàn)、動畫、以及交互等等;同時它會遇到比較大量的數(shù)據(jù),從而延緩我們的渲染過程,這就是一個挑戰(zhàn)。

      我來自 ECharts 團(tuán)隊,所以今天講的內(nèi)容都是 ECharts 在這個課題中所遇到的部分經(jīng)歷。ECharts 是一個數(shù)據(jù)可視化圖表庫,主要在瀏覽器環(huán)境下運(yùn)行,我們今天所講的也都是在瀏覽器中運(yùn)行 JS 來進(jìn)行渲染時的優(yōu)化經(jīng)驗。

      1大數(shù)據(jù)渲染為何放在前端?

      首先我們看看為什么要在前端進(jìn)行大數(shù)據(jù)渲染。這里的前端就是通常意義上的瀏覽器環(huán)境。為什么我們不在后端先進(jìn)行數(shù)據(jù)降級處理,然后再返回到瀏覽器?

      有兩點考慮,一是在后端處理需要額外的計算資源,本來在客戶端的分布式計算全都挪到后端,會需要額外的資源,比較麻煩。

      第二是不易交互。可視化分析時,你不光要看數(shù)據(jù)整體,可能還需要縮放,看各種細(xì)節(jié)。如果后端數(shù)據(jù)降級了返回給前端,細(xì)節(jié)就丟掉了,不太容易做這種比較流暢的交互。所以能在前端做的還是盡量在前端,如果做不到再到后端進(jìn)行數(shù)據(jù)降級處理。

      2前端處理交互時的挑戰(zhàn)

      前端處理交互會面臨哪些挑戰(zhàn)?瀏覽器環(huán)境有性能限制,還會有實時性要求。不僅要求交互很流暢,而且有時實時數(shù)據(jù)每隔一秒鐘或者幾百毫秒全量刷新一次,這需要圖表庫做到性能足夠優(yōu)化。為了做這些事情我們需要解決三點問題:

      1. 渲染的時間不能太長,比如說瀏覽器彈出一個窗口說你的一個長的執(zhí)行腳本是不是要?dú)⒌簦磕遣恍小?/span>
      2. 交互不卡頓。
      3. 呈現(xiàn)效果流暢,不能渲染了半天才把整個東西呈現(xiàn)給用戶,如果有可能就要渲染了多少就趕緊呈現(xiàn)多少。

      3優(yōu)化要點

      下面我們挑一些優(yōu)化點來給大家分析。

      降采樣

      第一個是降采樣。降采樣是普遍采用的一種優(yōu)化方式。比如說我這里一個例子是一千萬折現(xiàn)圖的 LTTB 降采樣。

      雖然這里面有一千萬個點,但是我們屏幕的尺寸沒有那么大,至多也就一千多個像素,所以大部分像素點如果要畫出來都是重疊的,你沒必要把所有點全都進(jìn)行數(shù)據(jù)到視覺的映射,然后 Layer out。你可以選一個窗口,在這個窗口內(nèi)挑一些代表的點來渲染,這就是降采樣。這樣就會極大優(yōu)化性能。

      另一件事就是你怎么挑這個點?你需要保留足夠的局部特征,比如說局部最大值最小值要保留,因為這些細(xì)節(jié)往往是需要人關(guān)注的,不能夠抹去。LTTB 算法就起到這個作用,經(jīng)過這種優(yōu)化以后縮放會比較流暢。

      但降采樣也并非能夠解決所有的事情,它有一定的要求,需要你的數(shù)據(jù)有一定的局部性:你的數(shù)據(jù)的排序和你最后屏幕上展現(xiàn)出來的順序是一致的。要換成散點圖,點是分散在各處的,你就不太容易去選擇這些點,因為它根本就沒有重疊性了。第二個要求圖形展示的特征是能夠真的完全重疊的,比如要是一個平行坐標(biāo)系,這些都是線,不能完全重疊,就不太容易去采樣。

      減少 Canvas 狀態(tài)切換

      下一件事情是減少 Canvas 狀態(tài)切換。ECharts 底層可以用 Canvas 渲染,也可以用 SVG 渲染,但我們在做大數(shù)據(jù)渲染的時候基本上都會用 Canvas。Canvas 的 API 設(shè)計足夠基礎(chǔ),也足夠快,能夠承載大數(shù)據(jù)的渲染。即便如此我們?nèi)孕枰獙λ?API 進(jìn)行一定的優(yōu)化。

      先講一下 ECharts 和 ECharts 所基于的庫是怎么樣去使用 Canvas 的。

      最下面這個灰框里面是 Canvas 的 API。作為一個比較復(fù)雜的應(yīng)用來說,它一般不會去直接在這些最原始的,命令式 API 之上進(jìn)行業(yè)務(wù)邏輯開發(fā),一般還是會抽象一層,就把這些需要繪制的東西抽象成一個個元素實例。每一個元素自己會維護(hù)我們需要繪制的這個元素上面的各種屬性,比如說它的縮放尺寸 scale X 跟 Y 之類的東西,全都作為元素這個實例的屬性維護(hù)著。每一幀的時候遍歷這些元素對它排序,然后讓它自己去繪制自己,也就是說把這些屬性最終轉(zhuǎn)換為 Canvas 的渲染指令,然后輸出給瀏覽器,讓瀏覽器繪制。

      在真正渲染的時候,我們已經(jīng)有了元素,上面有很多我們配置好的屬性,然后它先把這些屬性值,set 到 Canvas2D 的這個 context 上面去。下一步 built Path,就是根據(jù) path 相關(guān)的屬性,把整個路徑給 Built 出來。

      Canvas 這些接口雖然足夠快,但還是有一定開銷的。因為我們需要挑戰(zhàn)的數(shù)據(jù)量本身可能會是百萬、千萬的數(shù)據(jù),這個 fillStyle 開銷累積起來還是很明顯的,百萬次可以達(dá)到 100ms 以上。所以我們需要對這里進(jìn)行優(yōu)化。

      那么 fillStyle 為什么會有這些開銷?可以去看一看瀏覽器的實現(xiàn),比如說這個是 Blink 的實現(xiàn),在 fillStyle 里它可能會需要對字符串表達(dá)的顏色進(jìn)行解析,有一定開銷。為了優(yōu)化、避免掉這些東西,如果這次的 style 和上次的 style 相同的話,就不再向 Canvas 的 context 上設(shè)置。在海量數(shù)據(jù)繪制的場景下,前后的這些屬性會有差異的情況并不多,大多數(shù)會用同樣的顏色,因為數(shù)據(jù)量大的時候用各種差異性的東西已經(jīng)不太能夠看清了。

      合并

      下一件事是合并。比如說我上面一行顯示的是繪制的過程中多個 set style,再 build path,再 set style,以此類推。但如果強(qiáng)制把它合并掉,從業(yè)務(wù)層就認(rèn)為它們的 Style 完全相同,只 set style 一次就可以了,連比較都不需要比較。這樣就不需要在每個 element 里維護(hù)一個 build path 的結(jié)果,而是用一個數(shù)組來存放結(jié)果,就減少了很多內(nèi)存開銷以及 JS 開銷等等。這種方式也是有限制的,就是它并不支持多個不同 style 的場景。

      一維數(shù)組和 TypedArray

      下一個優(yōu)化方式非常常見和重要,就是用一維數(shù)組或者 TypedArray。因為我們在渲染圖表的時候,絕大多數(shù)都是在渲染一些二維表,比如說每一行都是一條條數(shù)據(jù)項,每一列是一個一個緯度。就數(shù)據(jù)來說,我們最直觀的就是用二維數(shù)組來表達(dá),或者有可能還用 Object 組成的數(shù)組來表達(dá)。這些表達(dá)非常直觀,但是它會占用更多內(nèi)存,因為每一項都是一個數(shù)組、一個對象。

      處理大數(shù)據(jù)的時候把它降維,降成一維的,那么讀寫的時候也就稍微加一點計算量,但并不多,這樣的話會節(jié)省很多內(nèi)存,并且速度會快很多。比如說我下面這一個圖里面演示用二維數(shù)組來繪制一個折線圖,大概五百萬數(shù)據(jù),初始化時間用了將近 5 秒鐘。

      下面這個滾動的小球相當(dāng)于額外的一個動畫,這個動畫只是想演示出來在 ECharts 進(jìn)行交互改變的時候,是不是會影響到頁面其他部分額外動畫的流暢度。比如說我上面進(jìn)行縮放,下面的這個動畫就很卡,那就是影響到了。

      最下面這個豎線表示它是一幀一幀的長度,上面一個格大概是 16.7 毫秒。如果這個豎線間隔變得很長,就說明一幀的時間變得很長。對于五百萬數(shù)據(jù),二維數(shù)組還是相對來說比較卡,但如果換成一維數(shù)組就會好很多。首先它初始化時間大概只有 400 多毫秒,并且交互的卡頓時間就會好很多,雖然仍然每一幀的時間稍微長一點,但已經(jīng)足夠可以接受。但它也稍微有一點弊端,就是它非常大的時候可能會崩掉。比如在我的機(jī)器上,一個數(shù)組到了三千萬瀏覽器就會崩掉。

      最好的情況下還是 TypedArray,它申請的時候就是定長了,相當(dāng)于你完全自己管理這個內(nèi)存空間,并且每一個數(shù)據(jù)項都是固定類型的,所以有更好的穩(wěn)定性。當(dāng)然它的弊端是你自己要去管理它,要記錄它的長度,如果超長的話,你自己重新申請一片空間把原來的復(fù)制過來,要去自己實現(xiàn)這些數(shù)據(jù)結(jié)構(gòu)。

      GC 減少

      GC 是不可忽視的一個因素,因為在數(shù)據(jù)量大的時候,GC 在每一幀中的消耗可能會很影響流暢度。

      上面貼了一個圖,Minor GC 就花了 5 毫秒,可是你一幀也就幾十毫秒,或者十幾毫秒。想要 GC 能夠可控、減的很少,可能有很多不太確定的方式。在我們優(yōu)化中使用過的方式有及時釋放,意思就是說,臨時的一個小對象對性能情況影響比較小,比如說我在函數(shù)里聲明一個臨時的對象,這個對象也沒有掛在哪,用完了后就釋放掉了,沒有太大的影響。但是另一種情況有影響,就是我這個臨時對象實際上掛了一個什么東西上,我在下一個階段可能又使用了它,再在下一個階段才準(zhǔn)備把它釋放掉,這時候它的釋放可能就會影響很多了。GC 的時間是非常快的,但是你如果幾次的清掃都沒有能夠釋放,這種臨時的小對象存著就很影響機(jī)器的開銷,但如果把它都存成一個整個的 TypedArray 就會好很多。

      前面講的這些手段都是在盡量減少一些開銷。但從理論上說,數(shù)據(jù)可視化的過程就是從用戶的數(shù)據(jù)轉(zhuǎn)換成最終渲染的指令的過程。數(shù)據(jù)越多指令就越多,渲染的時間就越長。但 UI 系統(tǒng)允許不可打斷的渲染時長是有限的,它需要 60hz,或者降低一點的 20hz,轉(zhuǎn)換成時間的話可能 16 毫秒、50 毫秒,或者更長一點 100 毫秒都還能接受,再長一點就明顯卡頓了。這里的有限和前面說的數(shù)據(jù)增長是矛盾,這個上限就導(dǎo)致了我們再怎么優(yōu)化總歸會到一個瓶頸。下面所講的一些手段就是要打破這個瓶頸。

      并發(fā)

      我們可能會想到用并發(fā)的手段,比如說我利用操作系統(tǒng)本身提供的多線程機(jī)制,或者把數(shù)據(jù)整個持續(xù)的渲染任務(wù)分成順序不太相關(guān)的一些子任務(wù),自己來調(diào)度。

      首先來說多線程的嘗試,在瀏覽器里面多線程是只能用 Web Worker。在講這個之前先看一下 ECharts 的渲染管線。

      最左邊是用戶輸入,然后是一系列的階段,進(jìn)行渲染形成 Elements,最后轉(zhuǎn)換成渲染指令。這流程很長,是 CPU 密集型過程。如果用多線程,用 Web Worker 嘗試,就把流程都放到 Worker 里進(jìn)行,主的 JS 線程只做用戶輸入,或者把那些最后得到的 Canvas 渲染指令輸出出來,然后用戶的鼠標(biāo)之類的交互又傳給 Worker 線程,得到結(jié)果再傳給主線程。

      這個結(jié)構(gòu)是可以工作,但是它也有問題:它的交互可能不同步,大數(shù)據(jù)渲染實際上還是很慢的。雖然用戶交互沒有阻塞,但是沒有真的解決 Worker 線程里渲染慢的這個問題,看起來這個結(jié)果還是不很好。而且比如說拖動時它很不跟手,雖然用戶交互不阻塞,但用戶的交互響應(yīng)還是在 Worker 線程,響應(yīng)完了還是要更新視圖,這個 Worker 線程忙于計算,它就沒有足夠短的時間來響應(yīng)這些用戶交互了,結(jié)果效果還是不行。所以說盡管多線程可以在主線程里不會影響到其他,但是渲染問題還是避免不了要在單線程上面解決。

      還有些其他的問題。JS 多線程有一個很大的弊端就是它的內(nèi)存不共享。渲染的過程中有需要給用戶以回調(diào),回調(diào)用戶程序,這種回調(diào)如果放在一個多線程的環(huán)境下不能共享,它就只能來回傳輸,不光是要跨線程,而且要有傳輸開銷。基于這些東西來說,這個多線程渲染后續(xù)沒有真的落實到產(chǎn)品中,因為它可能帶來的收益有限,只是作為一個嘗試的過程,而最根本的還是要去解決單線程中渲染的優(yōu)化。

      漸進(jìn)渲染

      接下來講的是漸進(jìn)渲染方式。漸進(jìn)渲染能做到第一不阻塞交互,第二盡快渲染出效果,意思就是說它把用戶的長任務(wù)分割成一些各種各樣的短任務(wù),然后做調(diào)度,然后實現(xiàn)一部分短任務(wù),然后讓它響應(yīng)一下用戶的交互,再執(zhí)行下一步。

      這就是長任務(wù),兩個紅線表示的是幀。把這個任務(wù)分割成多個子任務(wù)就能響應(yīng)很多次用戶。

      沒有漸進(jìn)渲染之前,整個 data 走完這四個過程最后才上屏,這一幀會比較長。如果有了漸進(jìn)渲染,就把整個 data 分成好多好多 chunk,每個 chunk 走完這四個過程就直接上屏了,而且這一個幀比較短的情況下,就能夠響應(yīng)下一次的用戶交互。

      漸進(jìn)渲染里面可能會涉及一些程序結(jié)構(gòu)的調(diào)整。在沒有漸進(jìn)渲染之前,以這個 layout 過程為例,它就是從 0 一直取到 data 的末尾。

      而有了漸進(jìn)渲染,所有的轉(zhuǎn)化過程沒變,但它只是從 start 處理到 end,這是由外層的調(diào)度器來決定的。

      這里還有一點就是層的問題,因為它是在多幀中逐漸出來后續(xù)效果的。這里就是一個漸進(jìn)渲染的例子,中間這個波浪的中間線就是一大堆散點,但是上面放了一個餅圖作為另一個層,意思是讓餅圖遮蓋著它。如果是不分層,你后續(xù)出來的這個點就會覆蓋到餅圖上面。所以漸進(jìn)渲染要有單獨(dú)的層,上面不漸進(jìn)渲染的東西和底下的東西都會分多層。

      分片

      漸進(jìn)渲染的下一個問題就是分片,每一片分多大?最開始都是用自己的配置,比如說我配置成每片三千,這個在很多場景都是可以用的,因為大家需要處理大數(shù)據(jù)的這些機(jī)器性能也都不錯。但它沒辦法適應(yīng)不同的環(huán)境,CPU 慢下來幀率就明顯降下來了,這就是一個弊端。

      如何解決這個弊端呢?我們先把整個渲染流程抽象成一個最簡單的結(jié)構(gòu),就是 onframe。每個 onframe 從 0 走到 3000,里面處理單個數(shù)據(jù)項,處理完了 3000 個以后 break 出來,再申請下一個 frame,繼續(xù)這個過程,這是固定值的過程。

      但是如果我們要不固定值,那么我們先把這個過程改成這么一個抽象。就是一個 task 先一直循環(huán),循環(huán)不是固定三千,而是一直在檢查是不是應(yīng)該 break,是的話就跳出來,不是的話就時序處理一個一個的單點。

      那么怎么來判斷我是不是應(yīng)該跳出來呢?有 requestIdleCallback 能夠讓你知道現(xiàn)在還有多少時間剩余,你可以邊進(jìn)行你的工作,邊用 API 得到更短的剩余時間,看看是不是應(yīng)該 break。這就能夠保證幀率是非常穩(wěn)定并且非常快的。但這個看起來理想,但它是有問題的。第一個它并不足夠積極,因為它更多是為了后臺任務(wù)來設(shè)計的,它優(yōu)先保證幀率,而并不優(yōu)先保證你得到回調(diào)的機(jī)會。比如說它在有些安卓手機(jī)上面滑動的時候甚至得不到回調(diào),對于一個 UI 來說這樣就不太合適了,如果你滑了半天,UI 不進(jìn)行任何更新那是不行的。第二個就是它的兼容性還一直是有問題的。

      如果用另一種方式,每次就是一直計時間,如果到了 16 毫秒就 break,然后繼續(xù)申請下一幀,這樣行不行?這個也不完全行,因為我們現(xiàn)在的瀏覽器做的處理用戶輸入以及后續(xù)過程都是按照幀來驅(qū)動的,每一幀以固定的流程來做這些。給 JS 執(zhí)行這些事情只是這個流程的一部分,它還有很多別的工作。就比如說我現(xiàn)在 JS 提交了很多 Canvas 指令,它還需要把這些 Canvas 指令轉(zhuǎn)成繪制指令去繪制,這些東西也是耗時的,要想為這些東西預(yù)留時間也不容易。

      下一個思路是,我既然不能夠留時間,我就把這個粒度縮的更小一點,比如我每五毫秒為一個單位去 break,break 就留出了系統(tǒng)調(diào)度的時間。你可能會立刻去調(diào)度下一個 5 毫秒的宏任務(wù),也可能就到了一個幀的邊界,你就會去進(jìn)行下一幀的周期來響應(yīng)用戶輸入。這種方式用的是 MessageChannel,因為它是一種最快的申請宏任務(wù)的方式。如果 MessageChannel 里什么都不干,它在一個幀里面能一直申請無數(shù)個任務(wù)。

      如果是這樣的方式來實現(xiàn),剛才的代碼就變成這樣,while 的條件變成是否小于 5 毫秒。如果是 5 毫秒之內(nèi)就執(zhí)行每一個數(shù)據(jù)處理,如果跳出來就申請下一個宏任務(wù)。這種節(jié)奏看起來挺好,但是它也有一些弊端,它對程序結(jié)構(gòu)是有一定要求的,就是在實踐中它渲染總的時長會變多,為什么?因為它粒度小導(dǎo)致一些重復(fù)工作的開銷。因為現(xiàn)實中不一定能抽象得那么好,可能每次渲染之前需要做一些別的工作,這些工作不一定全能拆開來循環(huán)。這些工作占用的時間過多的話,可能會導(dǎo)致總的渲染時長變長。如果是沒有這種制約的話,用這種方式也是挺好的。

      樸素方法:自動調(diào)整片的尺寸

      再換一種方式就是樸素的自動調(diào)整片的尺寸。我還是用一個固定的 step 值來渲染,但是這個 step 值是自動調(diào)整的。我邊渲染邊統(tǒng)計時間,大概估摸著這個 step 調(diào)整成多少,這個幀率能夠逼近于多少這么一個狀態(tài),來做自動調(diào)整。這就主要看你的公式做得是不是足夠好了。

      4總結(jié)

      總體來說,各種各樣的優(yōu)化方案都有各種利弊,我們要根據(jù)具體的場景選擇合適的方法。

      最后還有一些小要點,就是渲染中會有一些重繪的體驗優(yōu)化。比如說一個 K 線圖的漸進(jìn)渲染,如果每次都是從左到右渲染就挺傻的。但如果我只是做一個簡單的變化,把漸進(jìn)渲染片的執(zhí)行順序變成了取一個模,這樣體驗就好很多。

      這是一個路線圖的渲染,每次我拖動的時候因為破壞了原來的環(huán)境,它就必須重新渲染,這樣體驗也不是很好。這個在 2D 渲染里不太好解決,但如果是用 EChartsGL 來變成 3D 就好辦,因為它機(jī)制不一樣。它進(jìn)行這個 zoom 是通過攝像頭改變,實際上已有的數(shù)據(jù)不必擦除,可以重用了,這樣的話就會好很多。

       
      (文/媒體小英)
      免責(zé)聲明
      本文僅代表作發(fā)布者:媒體小英個人觀點,本站未對其內(nèi)容進(jìn)行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,需自行承擔(dān)相應(yīng)責(zé)任。涉及到版權(quán)或其他問題,請及時聯(lián)系我們刪除處理郵件:weilaitui@qq.com。
       

      Copyright ? 2016 - 2025 - 企資網(wǎng) 48903.COM All Rights Reserved 粵公網(wǎng)安備 44030702000589號

      粵ICP備16078936號

      微信

      關(guān)注
      微信

      微信二維碼

      WAP二維碼

      客服

      聯(lián)系
      客服

      聯(lián)系客服:

      在線QQ: 303377504

      客服電話: 020-82301567

      E_mail郵箱: weilaitui@qq.com

      微信公眾號: weishitui

      客服001 客服002 客服003

      工作時間:

      周一至周五: 09:00 - 18:00

      反饋

      用戶
      反饋

      午夜久久久久久网站,99久久www免费,欧美日本日韩aⅴ在线视频,东京干手机福利视频
        <strike id="ca4is"><em id="ca4is"></em></strike>
      • <sup id="ca4is"></sup>
        • <s id="ca4is"><em id="ca4is"></em></s>
          <option id="ca4is"><cite id="ca4is"></cite></option>
        • 主站蜘蛛池模板: 成人性开放大片| 欧美日韩激情在线| 尤物国产在线精品福利一区| 国产a级黄色毛片| 中文字幕无码av激情不卡| 被啪羞羞视频在线观看| 日本全黄三级在线观看| 国产亚洲欧美精品久久久| 久久免费公开视频| 菠萝蜜视频在线播放| 日本一区二区三区久久| 国产丝袜第一页| 中文字幕免费看| 精品久久久久久无码中文字幕一区| 小坏蛋轻点阿受不了漫画| 免费人成网站在线高清| a级成人毛片免费图片| 波多野结衣免费在线| 国产精品白丝在线观看有码| 亚洲午夜久久久精品影院| 91手机视频在线| 无翼乌全彩里番蛇姬本子| 午夜精品一区二区三区在线观看 | 在线永久免费观看黄网站| 亚洲欧美日韩国产一区二区三区精品| 97久人人做人人妻人人玩精品| 欧美激情一区二区三区在线 | 免费v片视频在线观看视频| 99久久伊人精品综合观看| 欧美性受xxxx| 国产女精品视频在ktv| 丰满妇女强制高潮18XXXX| 精品久久久久久久久久中文字幕 | 欧美国产日韩911在线观看| 国产女主播喷水视频在线观看| 丰满少妇高潮惨叫久久久| 福利视频1000| 国产精品入口在线看麻豆| 久久五月精品中文字幕| 精品国偷自产在线| 国产美女口爆吞精普通话|