整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          帶你區分幾種并行

          帶你區分幾種并行

          要:在實際應用中,影響并行加速比的因素主要是串行計算、并行計算和并行開銷三方面。

          本文分享自華為云社區《高性能計算(2)——萬丈高樓平地起-云社區-華為云》,作者: 我是一顆大西瓜。

          存儲方式

          從物理劃分上 共享內存和分布式內存是兩種基本的并行計算機存儲方式 除此之外 分布式共享內存也是一種越來越重要的并行計算機存儲方式

          指令和數據

          • [小粒度]根據一個并行計算機能夠同時執行的指令與處理數據的多少 可以把并行計算機分為 SIMD
          • [大粒度]按同時執行的程序和數據的不同 又提出了SPMD Single-Program Multuple-Data 單程序多數據并行計算機和MPMD

          根據指令的同時執行和數據的同時執行,計算機系統可以分成以下四類:

          • 單處理器,單數據 (SISD)
          • 單處理器,多數據 (SIMD)
          • 多處理器,單數據 (MISD)
          • 多處理器,多數據 (MIMD)

          斷續器

          單處理器單數據就是“單CPU的機器”,它在單一的數據流上執行指令。在SISD中,指令被順序地執行。

          對于每一個“CPU時鐘”,CPU按照下面的順序執行:

          • Fetch: CPU 從一片內存區域中(寄存器)獲得數據和指令
          • 解碼: CPU對指令進行解碼
          • Execute: 該執行在數據上執行,將結果保存在另一個寄存器中

          這種架構(馮·諾依曼體系)的主要元素有以下:

          • 中心內存單元:存儲指令和數據
          • CPU:用于從內存單元獲得指令/數據,對指令解碼并順序執行它們
          • I/O系統:程序的輸入和輸出流

          傳統的單處理器計算機都是經典的SISD系統。下圖表述了CPU在Fetch、Decode、Execute的步驟中分別用到了哪些單元:

          管理信息系統

          這種模型中,有n個處理器,每一個都有自己的控制單元,共享同一個內存單元。在每一個CPU時鐘中,從內存獲得的數據會被所有的處理器同時處理,每一個處理器按照自己的控制單元發送的指令處理。在這種情況下,并行實際上是指令層面的并行,多個指令在相同的數據上操作。能夠合理利用這種架構的問題模型比較特殊,例如數據加密等。因此,MISD在現實中并沒有很多用武之地,更多的是作為一個抽象模型的存在。

          辛德

          SIMD計算機包括多個獨立的處理器,每一個都有自己的局部內存,可以用來存儲數據。所有的處理器都在單一指令流下工作;具體說,就是有n個數據流,每個處理器處理一個。所有的處理器同時處理每一步,在不同的數據上執行相同的指令。

          很多問題都可以用SIMD計算機的架構來解決。這種架構另一個有趣的特性是,這種架構的算法非常好設計,分析和實現。限制是,只有可以被分解成很多個小問題(小問題之間要獨立,可以不分先后順序被相同的指令執行)的問題才可以用這種架構解決。很多超級計算機就是使用這架構設計出來的。例如Connection Machine(1985年的 Thinking Machine)和MPP(NASA-1983).我們在第六章 GPU Python編程中會接觸到高級的現代圖形處理器(GPU),這種處理器就是內置了很多個SIMD處理單元,使這種架構在今天應用非常廣泛。

          MIMD

          在費林分類中,這種計算機是最廣泛使用、也是最強大的一個種類。這種架構有n個處理器,n個指令流,n個數據流。每一個處理器都有自己的控制單元和局部內存,讓MIMD架構比SIMD架構的計算能力更強。每一個處理器都在獨立的控制單元分配的指令流下工作;因此,處理器可以在不同的數據上運行不同的程序,這樣可以解決完全不同的子問題甚至是單一的大問題。在MIMD中,架構是通過線程或進程層面的并行來實現的,這也意味著處理器一般是異步工作的。這種類型的計算機通常用來解決那些沒有統一結構、無法用SIMD來解決的問題。如今,很多計算機都應用了這中間架構,例如超級計算機,計算機網絡等。然而,有一個問題不得不考慮:異步的算法非常難設計、分析和實現。

          并發和并行

          并行類型

          幾種并行區分

          程序、線程、進程和超線程

          • 程序程序是一組指令的有序集合。它本身沒有任何運行的含義,只是存在于計算機系統的硬盤等存儲空間中一個靜態的實體文件。比如Linux系統下的binary excutable,windows系統下的exe
          • 進程進程是處于動態條件下由操作系統維護的系統資源管理實體。進程具有自己的生命周期, 反映了一個程序在一定的數據集上運行的全部動態過程。需要加載到內存中,點開一個exe就是開啟了一個進程
          • 線程。線程則是進程的一個實體,是比進程更小的能獨立運行的基本單位,是被系統調度和分配的基本單元。線程自身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源 (如程序計數器、一組寄存器和調用堆棧), 但它與同屬一個進程的其他線程共享所屬進程所擁有的全部資源,同一個進程的多個線程可以并發執行,從而提高了系統資源的利用率
          • 超線程超線程技術就是利用特殊的硬件指令,把兩個邏輯內核模擬成兩個物理芯片,讓單顆CPU都能進行線程級并行計算,進而兼容多線程操作系統和軟件。一般一個CPU對應一個線程,通過超線程可以達到比如8核16線程

          老生常談,線程和進程的區別和聯系

          1. 一個程序的執行至少有一個進程,一個進程至少包含一個線程(主線程)。
          2. 線程的劃分尺度小于進程,所以多線程程序并發性更高。
          3. 進程是系統進行資源分配和調度的一個獨立單位,線程是CPU調度和分派的基本單位。同一進程內允許多個線程共享其資源。
          4. 進程擁有獨立的內存單元,即進程之間相互獨立;同一進程內多個線程共享內存。因此,線程間能通過讀寫操作對它們都可見的內存進行通信,而進程間的相互通信則需要借助于消息的傳遞。
          5. 每個線程都有一個程序運行的入口,順序執行序列和程序運行的出口,但線程不能單獨執行,必須依存于進程中,由進程控制多個線程的執行
          6. 進程比線程擁有更多的相應狀態,所以創建或銷毀進程的開銷要比創建或銷毀線程的開銷大得多。因此,進程存在的時間長,而線程則隨著計算的進行不斷地動態地派生和縮并。
          7. 一個線程可以創建和撤銷另一個線程。而且同一進程中的多個線程共享所屬進程所擁有的全部資源;同時進程之間也可以并行執行,從而更好地改善了系統資源的利用率。

          線程綁定

          計算機系統是由一個或多個物理處理器和內存組成,運行的程序會將內存分為兩個部分,一部分是共享變量使用的存儲區域, 另一部分供各線程的私有變量使用的存儲區域。線程綁定是將線程綁定在固定的處理器上, 從而在線程與處理器之間建立一對一的映射關系。如果不進行線程綁定,線程可能在不同的時間片運行在不同的處理器上。我們知道,每個處理器是有自己的多級緩存的,如果線程切來切去,那么cache命中率肯定不高,程序性能也會受到影響。通過線程綁定,程序能夠獲得更高的cache利用率從而提高程序性能。c++中如何進行線程綁定可以參考https://www.cnblogs.com/wenqiang/p/6049978.html

          并行算法評價

          理論上來說,n個相同的cpu理論上能提供n倍的計算能力。

          但是在實際過程中,并行開銷會導致總的執行時間無法線性地減少。這些開銷分別為:

          1. 線程的建立和銷毀、 線程和線程之間的通信、 線程間的同步等因素造成的開銷。
          2. 存在不能并行化的計算代碼,造成計算由單個線程完成, 而其他線程則處于閑置狀態。
          3. 為爭奪共享資源而引起的競爭造成的開銷
          4. 由于各cpu工作負載分配的不均衡和內存帶寬等因素的限制,一個或多個線程由于缺少工作或因為等待特定事件的發生無法繼續執行而處于空閑狀態。

          并行加速比(加速比)

          加速比的定義是順序程序執行時間除以計算同一結果的并行程序的執行時間

          式中,t_sts為一顆CPU程序完成該任務所需串行執行時間;t_ptp為n顆CPU并行執行完成該任務所需時間。由于串行執行時間t_sts?為n顆CPU并行執行完成該 和并行執行時間t_ptp?有多種定義方式。 這樣就產生了五種不同的加速比的定義,即相對加速比、實際加速比、絕對加速比、漸近實際加速比和漸近相對加速比。

          并行效率(效率)

          在實際應用中,影響并行加速比的因素主要是串行計算、并行計算和并行開銷三方面。一般情況下, 并行加速比小于CPU的數量。但是,有時會出現一種奇怪的現象,即并行程序能以串行程序快n倍的速度運行,稱為超線性加速比。產生超線性加速的原因在于CPU訪問的數據都駐留在各自的高速緩存Cache中, 而高速緩存的容量比內存要小, 但讀寫速度卻遠高于內存。

          衡量并行算法的另一個主要標準是并行效率,它表示的是多顆CPU在進行并行計算時單顆CPU的平均加速比。

          理想并行效率為1表明全部CPU都在滿負荷工作。通常情況下,并行效率會小于1, 且隨CPU數量的增加而減小。

          伸縮性

          伸縮性用于度量并行機器高效運行的能力,代表跟處理器數量成比例的計算能力 (執行速度)。如果問題的規模和處理器的數量同時增加,性能不會下降。

          阿姆德爾定律

          阿姆德爾定律廣泛使用于處理器設計和并行算法設計。它指出程序能達到的最大加速比被程序的串行部分限制。$S=1/(1-p) $中 1-p1?p 指程序的串行部分。它的意思是,例如一個程序90%的代碼都是并行的,但仍存在10%的串行代碼,那么系統中即使由無限個處理器能達到的最大加速比仍為9。

          古斯塔夫森定律

          古斯塔夫森定律在考慮下面的情況之后得出的:

          • 當問題的規模增大時,程序的串行部分保持不變。
          • 當增加處理器的數量時,每個處理器執行的任務仍然相同。

          古斯塔夫森定律指出了加速比S(P)=P-\alpha (P-1)SP)=P?αP?1), PP 為處理器的數量, SS S 為加速比,\alphaα 是并行處理器中的非并行的部分。作為對比,阿姆德爾定律將單個處理器的執行時間作為定量跟并行執行時間相比。因此阿姆德爾定律是基于固定的問題規模提出的,它假設程序的整體工作量不會隨著機器規模 (也就是處理器數量) 而改變。古斯塔夫森定律補充了阿姆德爾定律沒有考慮解決問題所需的資源總量的不足。古斯塔夫森定律解決了這個問題, 它表明設定并行解決方案所允許耗費的時間的最佳方式是考慮所有的計算資源和基于這類信息。

          點擊下方,第一時間了解華為云新鮮技術~

          華為云博客_大數據博客_AI博客_云計算博客_開發者中心-華為云

          Hamsters是一個能讓JavaScript代碼并行執行的原生庫,它可以讓你面向高性能的JavaScript編程,它是一個開源項目,Github上標星4k+。它的目的就是讓你更加容易的利用多線程的強大功能來并行編程實現性能的提升!



          Github

          https://github.com/austinksmith/Hamsters.js

          特性

          • 多功能,通過跨多個線程來最大限度地提高性能。

          • 自動數據聚合,自動將問題分解成較小的部分,并與單個輸出并行執行。

          • 自動分類,按字母順序或數字自動排序輸出。

          • LEGACY 支持。

          • 備忘,計算一次后不再浪費 cpu 周期做同樣的工作

          • 開放源代碼,100%開源代碼庫,根據Artistic License 2.0發布

          支持的環境

          • 所有主流瀏覽器、IE9 +

          • 現有 Web workers

          • Javascript shell 環境

          • React Native

          • Node.js


          如何使用?

          安裝使用


           bower install WebHamsters
          //OR
          npm install hamsters.js
          

          • 1、普通HTMl項目中使用
          <!-- HTML4 and (x)HTML -->
           <script type="text/javascript" src="path/to/hamsters.js">
           <!-- HTML5 -->
           <script src="path/to/hamsters.js"></script>
          

          • 2、React Native
           import hamsters from 'path/to/hamsters';
          

           import Worker from '...';
           import hamsters from 'hamsters.js';
           hamsters.init({
           Worker: Worker
           });
          

          • 3、Nodejs
          var hamsters=require('hamsters.js');
          

           var Worker=require('...').Worker;
           var hamsters=require('hamsters.js');
           hamsters.init({
           Worker: Worker
           });
          

          • 4、入門使用

          第一個要理解的是Hamsters.js是一個傳遞interfafce的消息,因此在使用庫調用函數時,我們需要通過將params對象(消息)傳遞給庫來指示庫如何操作。


           var params={
           bar: 'foo'
           };
           hamsters.run(params, ....);
          

          我們將使用的下一個參數將是我們想要在一個線程或線程中執行的邏輯,我們之前傳遞的params對象將在我們的函數的上下文中可訪問。現在應該能夠看到如何確保可以在線程中訪問變量和函數等不同的東西。

           hamsters.run(params, function() {
           var foo=params.bar;
           }); 
          

          第三個也是最后一個參數將是我們的onSuccess回調方法,此函數所需的唯一參數是輸出。

           hamsters.run(params, function() {
           var foo=params.bar;
           }, function(results) {
           console.log(results);
           });
          

          回到原始的params對象,為了從庫中獲得最佳性能和可靠性,需遵循一些約定。Hamsters.js的構建目標是并行而不是并發,盡管庫很好地實現了并行執行的主要目標。由于這樣做的各種設計決策是為了幫助實現這一目標,其中一個決定是庫如何在線程之間分割數據以便執行,因此您希望在多個線程中訪問的任何數組必須在您的參數內具有數組索引賓語。

          var params={
           array: [1, 2, 3, 4];
           };
           hamsters.run(params, function() {
           for(var i=0; i < params.array; i++) {
           rtn.data.push(params.array[i] * 4);
           }
           }, function(results) {
           });
          

          使用此約定,通過簡單地更改params對象中的一個選項,可以非常簡單地并行化上述方法。現在使用下面的方法,4個線程將完成相同的任務,每個線程僅在數組的一個數字上運行。

           var params={
           array: [1, 2, 3, 4];
           threads: 4
           };
           hamsters.run(params, function() {
           for(var i=0; i < params.array; i++) {
           rtn.data.push(params.array[i] * 4);
           }
           }, function(results) {
           });
          

          更進一步,庫使用一個名為rtn的內部返回對象,這個rtn對象對于庫具有一致的方式來處理線程輸出是至關重要的。因此,當我們想要從線程返回一個值時,我們需要將結果推送到rtn.data數組中。或者你可以讓你的rtn.data輸出,但只有你的輸出已經是一個數組。

           hamsters.run(params, function() {
           rtn.data.push(params.bar);
           }, function(results) {
           console.log(results); // 'foo';
           });
          

          通過以上代碼來看下它傳遞的參數

          var params={
           threads: Integer,
           aggregate: Boolean,
           dataType: String,
           memoize: Boolean
           sort: String,
           };
          

          1、threads這個可選參數將告訴庫執行先前聲明的函數的線程數,這允許在非常簡單的級別上更改您執行的線程數。如果您在此處未提供值,則庫默認值為1。

          2、aggregate此可選參數將告訴庫我們是否要在執行后將各個線程輸出聚合在一起,這僅在您跨多個線程執行并且默認為相關時才相關false。

          3、dataType此可選參數將通知庫我們的數據數組是JavaScript的類型化數組之一,在使用此參數時,庫將自動格式化輸出以匹配指定的輸出dataType。

          4、memoize此可選參數旨在與memoization模式結合使用,當啟用memoization模式時,此參數允許用戶控制單個函數級別是否緩存該函數的結果,其默認值為false。

          5、sort此可選參數將告訴庫按字母順序或數字順序自動對最終輸出進行排序,此參數的默認值為,null并且可以使用排序選項進行配置。

          params對象中包含的任何其他內容都可以在線程的執行上下文或多個線程中訪問,具體取決于您使用庫的方式。


          除了以上基本使用方式,你可以查看官方的相關文檔,有詳細的介紹和使用方式,如Promise、排序、memoization、可轉移對象、persistence、線程池、限制、設備等


          總結

          多線程和并行編程在Javascript中本身不是一件容易的事情,但是可借助第三方原生庫來彌補它,能讓你更加方便的進行多線程的編程,筆者可能并未介紹的非常清楚,如果你有這方面的需求,可以去查案Hamsters.js的相關文檔來體驗這種編程,希望對你有所幫助!

          要:在本文中,將重點關注網頁的初始渲染,即它從解析 HTML 開始。 我將探索可能導致高渲染時間的問題,以及如何解決它們。

          本文分享自華為云社區《頁面首屏渲染性能指南-云社區-華為云》,作者:Ocean2022。

          我們知道渲染頁面是一個將服務器的響應內容翻譯成圖片的過程。但是,如果你頁面的渲染性能比較糟糕的話,可能會帶來相對較高的跳出率。

          在本文中,我將重點關注網頁的初始渲染,即它從解析 HTML 開始。 我將探索可能導致高渲染時間的問題以及如何解決它們。

          關鍵渲染路徑(CRP)

          關鍵渲染路徑 (CRP) 是瀏覽器將代碼轉換為屏幕上可顯示像素的過程。 它有幾個階段,其中一些可以并行執行以節省時間,但有些部分必須依次完成。 如下圖所示:

          首先,一旦瀏覽器得到響應,它就會開始解析它。 當它遇到依賴項時,它會嘗試下載它。 如果它是一個樣式表文件,瀏覽器必須在渲染頁面之前完全解析它,這就是為什么 CSS 會阻塞渲染的原因。

          如果是腳本,瀏覽器必須:停止解析,下載腳本,然后運行。 只有在那之后它才能繼續解析,因為 JavaScript 程序可以改變網頁的內容(尤其是 HTML)。 這就是為什么 JS 會阻塞解析的原因。

          完成所有解析后,瀏覽器將構建文檔對象模型 (DOM) 和級聯樣式表對象模型 (CSSOM)。 將它們組合在一起得到渲染樹。 頁面的不顯示部分不會進入渲染樹,因為它只包含繪制頁面所需的數據。

          倒數第二步是將渲染樹進行布局, 這個階段也稱為回流:就是計算每個渲染樹節點的每個位置及其大小的地方。

          最后一步是繪制。 它會根據瀏覽器在前一階段計算得到的數據對像素進行著色。

          優化相關結論

          因此,根據這一過程,我們在優化性能方面,得出了一些結論。如果你要提升頁面初始化渲染的性能,你需要:

          • 減少傳輸的數據量
          • 減少瀏覽器必須下載的資源數量(尤其是阻塞的資源)
          • 減小 CRP 的長度

          同時,我們會根據下面 3 個指標來衡量優化的效率:

          • FP(First Paint)
          • FCP(First Contentful Paint)
          • FMP(First Meaningful Paint)

          除了渲染時間之外,還有其他一些因素也需要考慮。例如,你的頁面使用了多少阻塞資源以及下載它們需要多長時間

          性能優化策略

          鑒于我們在上面得出的結論,我們得出網站性能優化有三種主要策略:

          1. 盡量減少通過網絡傳輸的數據量;
          2. 減少通過網絡傳輸的資源總數;
          3. 縮短關鍵渲染路徑;

          1. 減少要傳輸的數據量

          首先,移除所有未使用的部分,例如 JavaScript 中無法訪問的函數、帶有從不匹配任何元素的選擇器的樣式以及被 CSS 永遠隱藏的 HTML 標簽。 其次,刪除所有重復項。

          然后,我建議建立一個自動壓縮過程。 例如,它應該從你的后端服務中刪除所有注釋(但不是源代碼)以及每個不包含附加信息的字符(例如 JS 中的空白字符)。

          完成后,我們剩下的可以是文本字符串。 這意味著我們可以安全地應用諸如 GZIP(大多數瀏覽器都理解)之類的壓縮算法。

          最后,還有緩存。 瀏覽器第一次呈現頁面時它不會有幫助,但它會在以后的訪問中節省很多。 但是,記住兩點至關重要:

          • 如果你使用 CDN,請確保支持緩存并在正確設置。
          • 與其等待資源的到期,不如 將文件的“指紋”嵌入到其 URL 中,以使本地緩存無效。

          當然,應該為每個資源定義緩存策略。 有些可能很少改變或根本不會改變,有的則是變化的很快,還有些文件包含敏感的信息(可以使用 “private” 防止 CDN 緩存私有數據)

          2. 減少關鍵資源的總數

          “關鍵”僅指網頁正確呈現所需的資源。 因此,我們可以直接跳過所有流程中沒有涉及的樣式以及腳本文件。

          樣式

          為了告訴瀏覽器不需要特定的 CSS 文件,我們應該為所有引用樣式表的鏈接設置媒體屬性。 使用這種方法,瀏覽器將只根據需要處理與當前媒體(設備類型、屏幕尺寸)匹配的資源同時降低所有其他樣式表的優先級。 例如,如果你將 media=“print” 屬性添加到引用樣式以打印頁面的樣式標記,則這些樣式不會在不打印媒體時干擾你的關鍵渲染路徑

          為了進一步改進該過程,你還可以將一些樣式內聯這可以為我們節省了至少一次到服務器的往返行程

          腳本

          如上所述,腳本會阻塞解析,因為它們可以改變 DOM 和 CSSOM。 為了避免這一點,所有腳本標簽都必須用屬性標記——異步或延遲。

          標有 async 的腳本不會阻塞 DOM 構建或 CSSOM,因為它們可以在 CSSOM 構建之前執行。 但請記住,內聯腳本無論如何都會阻止 CSSOM,除非你將它們放在 CSS 之上。

          相比之下,標有 defer 的腳本將在頁面加載結束時進行執行

          換句話說,使用 defer,腳本直到頁面加載事件被觸發后才會執行,而 async 讓腳本在文檔被解析時就會在后臺運行。

          3.縮短關鍵渲染路徑長度

          最后,應將 CRP 長度縮短到可能的最小值。

          作為樣式標簽屬性的媒體查詢將減少必須下載的資源總數。 script 標簽屬性 defer 和 async 將防止相應的腳本阻塞解析。

          使用 GZIP 壓縮、壓縮和歸檔資源將減少傳輸數據的大小(從而也減少數據傳輸時間)。

          內聯一些樣式和腳本也可以減少瀏覽器和服務器之間的往返次數。

          按照最新的最佳性能實踐理念,一個網站應該做的最快的第一件事就是展示 ATF 內容。 ATF 代表首屏這是立即可見的區域,無需滾動。 因此,最好以首先加載所需樣式和腳本的方式重新排列與渲染相關的所有內容,而其他所有內容都停止(既不解析也不渲染)。

          結尾

          總而言之,網站性能優化包含了網站響應的各個方面,例如緩存、設置 CDN、重構、資源優化等,但是所有這些都可以逐步完成。 作為 Web 開發人員,你可以將本文作為參考,并始終記住在實驗之前和之后測量性能。

          瀏覽器開發人員盡最大努力優化你訪問的每個頁面的網站性能,這就是瀏覽器通常實現所謂的“預加載器”的原因。 這部分程序會在你以 HTML 格式請求的資源之前進行掃描,以便一次發出多個請求并讓它們并行運行。 這就是為什么在 HTML(逐行)以及腳本標簽中保持樣式標簽彼此靠近的原因。

          此外,嘗試批量更新 HTML 以避免多個布局事件這些事件不僅由 DOM 或 CSSOM 中的更改觸發,而且在設備方向更改和窗口大小調整時也會觸發。

          點擊下方,第一時間了解華為云新鮮技術~

          華為云博客_大數據博客_AI博客_云計算博客_開發者中心-華為云


          主站蜘蛛池模板: 亚洲AV日韩综合一区| 精品视频在线观看你懂的一区| 精品一区二区三区在线视频观看 | 欧洲精品一区二区三区在线观看| 亚州日本乱码一区二区三区| 最美女人体内射精一区二区| 国产伦理一区二区| 国产MD视频一区二区三区| 日韩精品一区二区午夜成人版 | 伊人久久精品一区二区三区| 性色AV一区二区三区无码| 久久无码一区二区三区少妇| 无码少妇精品一区二区免费动态| 日韩毛片基地一区二区三区| 国产精品无码一区二区三区在 | 五月婷婷一区二区| 少妇无码一区二区二三区| 国产亚洲一区二区精品| 蜜桃传媒一区二区亚洲AV| 色窝窝无码一区二区三区色欲 | 日韩一区二区三区在线观看 | 国产精品一区在线观看你懂的| 精品一区二区三区视频在线观看| 国产乱子伦一区二区三区| 午夜福利国产一区二区| 少妇无码一区二区三区免费| 3d动漫精品啪啪一区二区免费| 尤物精品视频一区二区三区| 亚洲码欧美码一区二区三区| 免费高清在线影片一区| 日本成人一区二区| 久久久久人妻精品一区二区三区 | 精品人妻一区二区三区浪潮在线 | 久久精品一区二区三区中文字幕 | 精品一区精品二区制服| 精品国产区一区二区三区在线观看 | 3D动漫精品一区二区三区| 亚洲国产成人精品久久久国产成人一区二区三区综 | 精品无码一区二区三区爱欲| 乱码人妻一区二区三区| 麻豆精品一区二区综合av|