<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      .NET - 基于事件的異步模型

      注:這是大概四年前寫的文章了。而且我離開.net領(lǐng)域也有四年多了。本來不想再發(fā)表,但是這實(shí)際上是Active Object模式在.net中的一種重要實(shí)現(xiàn)方法,因此我把它掏出來發(fā)布一下。如果該模型有新的發(fā)展,望在評(píng)論中幫給出一個(gè)引用,以便其它讀者知曉。感激不盡

        基于事件的異步模型實(shí)際上是MSDN中講解異步編程時(shí)所提供的一個(gè)章節(jié)。但在閱讀這些章節(jié)時(shí),我覺得MSDN在一開始就將所有組成全部列出,然后再聯(lián)系到一起的講解次序并不適合我們的思維方式。因此在本文中,我將按照從易到難的方式逐步對(duì)該異步模型進(jìn)行講解。

        另外,我們對(duì)模型的討論將大量使用兩個(gè)名詞:用戶代碼及非用戶代碼。在本文中,它們分別代表使用該模型所暴露接口的代碼以及模型的內(nèi)部實(shí)現(xiàn)。

       

      模型簡(jiǎn)介

        您首先需要明白的一點(diǎn)是,該異步模型并不是在為您提供一種新的多線程編程技術(shù),而是為您提供了一些多線程編程規(guī)范方面的建議,從而為您的多線程解決方案提供更良好更靈活的接口和內(nèi)部組織。就其實(shí)現(xiàn)而言,基于事件的異步模型實(shí)際上是對(duì)其內(nèi)部所包含的異步操作的一個(gè)包裝。而按照該規(guī)范組織的異步調(diào)用對(duì)于用戶代碼而言則意義非常明確:如果需要以異步方式調(diào)用一個(gè)操作,并在操作完成后接到相應(yīng)的通知,而不需要和工作項(xiàng)進(jìn)行進(jìn)一步的通訊,那么可以直接調(diào)用一個(gè)函數(shù)并偵聽一個(gè)事件即可。甚至我們更可以通過偵聽報(bào)告工作進(jìn)度的事件來得到工作項(xiàng)進(jìn)度更新的信息。

        首先我們來看看異步模型的使用。假設(shè)我們有一個(gè)異步模型EventAsyncModel,而其擁有一個(gè)可以被異步執(zhí)行的任務(wù)SomeTask:

       1 void StartTask(EventAsyncModel asyncModel)
       2 {
       3     asyncModel.SomeTaskCompleted += OnSomeTaskCompleted;
       4     asyncModel.SomeTaskProgressChanged += OnSomeTaskProgressChanged;
       5 
       6     asyncModel.SomeTaskAsync();
       7 }
       8 
       9 void OnSomeTaskProgressChanged(…)
      10 {
      11 12 }
      13 
      14 void OnSomeTaskCompleted(…)
      15 {
      16 17 }

        上面的代碼展示了用戶代碼如何對(duì)基于事件的異步模型進(jìn)行使用:用戶通過一個(gè)成員函數(shù)SomeTaskAsync()插入一個(gè)工作項(xiàng),并在工作項(xiàng)狀態(tài)發(fā)生變化時(shí)發(fā)出一系列事件,如任務(wù)的進(jìn)度變化的SomeTaskProgressChanged或完成的SomeTaskCompleted。您可以看到,這些成員的名稱常常與您所需要插入的工作項(xiàng)的名稱相關(guān)。

       

        同時(shí)也可以看出,在基于事件的異步模型中,對(duì)多線程部分的處理被全部置于模型內(nèi)部,而僅僅暴露按照同步調(diào)用方式使用所需要的各個(gè)接口。也就是說,對(duì)于該模型的用戶代碼而言,其僅僅需要按照普通的單線程處理邏輯調(diào)用該模型所提供的接口即可,而不需要考慮有關(guān)多線程的任何問題。

       

      模型接口

        在大概了解了基于事件的異步模型之后,讓我們先從模型的表觀特征,模型的接口開始說起。經(jīng)過這一節(jié),相信您能了解該異步模型所提供的各個(gè)成員的確切使用方式。

        首先我們來講講異步操作的啟動(dòng)函數(shù)。對(duì)于一個(gè)需要轉(zhuǎn)化為異步操作的同步方法,我們常常需要按照一定的步驟將其轉(zhuǎn)化為異步調(diào)用。

        第一步要轉(zhuǎn)化的是函數(shù)名稱。在同步方法的轉(zhuǎn)化過程中,我們常常需要對(duì)函數(shù)的名稱進(jìn)行更改。更改后的函數(shù)名稱一方面可以提供較為明顯的“這是使用異步模型的成員函數(shù)”的提示,更可以令其與同步函數(shù)同時(shí)存在。一般情況下,異步函數(shù)會(huì)在相應(yīng)的同步函數(shù)名之后添加-Async后綴。例如對(duì)于同步函數(shù)SomeTask(),我們需要提供異步函數(shù)SomeTaskAsync()。

        在確定了異步函數(shù)的名稱之后,我們要轉(zhuǎn)化的就是函數(shù)的參數(shù)。一個(gè)異步函數(shù)所使用的參數(shù)應(yīng)與相應(yīng)同步函數(shù)所使用的參數(shù)相同。例如對(duì)于同步函數(shù)SomeTask(string parameters),異步函數(shù)的簽名應(yīng)為SomeTaskAsync(string parameters)。

        該過程中較為例外的是out和ref參數(shù)。如果同步調(diào)用中包含一個(gè)out參數(shù),那么它將存在于表示返回值的組成中,即異步模型的Complete事件中。而如果同步調(diào)用中包含一個(gè)ref參數(shù),那么它需要同時(shí)存在于異步函數(shù)的參數(shù)列表以及表示返回值的組成中。例如對(duì)于同步函數(shù)SomeTask(string parameters, out int result),轉(zhuǎn)化后的異步調(diào)用則為SomeTaskAsync(string parameters),同時(shí)Complete事件所傳回的參數(shù)將帶有參數(shù)result。同樣地,對(duì)于同步函數(shù)SomeTask(string parameters, ref int result),轉(zhuǎn)化后的異步調(diào)用應(yīng)為SomeTaskAsync(string parameters, int result),同時(shí)Complete事件所傳回的參數(shù)將帶有參數(shù)result。

        最后要說的是返回值。異步調(diào)用的返回值一般為void,這是因?yàn)樗诤瘮?shù)調(diào)用返回時(shí)還沒有得到工作項(xiàng)的最終執(zhí)行結(jié)果。

        既然異步調(diào)用并不將執(zhí)行結(jié)果通過返回值傳遞,那返回值應(yīng)從哪里得到呢?答案是工作項(xiàng)的完成消息。對(duì)于一個(gè)需要返回執(zhí)行結(jié)果的異步操作,軟件開發(fā)人員常常需要從AsyncCompletedEventArgs派生,并將表示執(zhí)行結(jié)果的成員添加到該派生類中。在異步工作項(xiàng)執(zhí)行完畢以后,AsyncCompletedEventArgs類的派生類將被Completed事件返回,并在派生類中記錄工作項(xiàng)的執(zhí)行結(jié)果。例如對(duì)于一個(gè)返回類型為int的同步函數(shù)int SomeTask(),我們首先需要?jiǎng)?chuàng)建AsyncCompletedEventArgs的派生類:

       1 public class SomeTaskCompletedArgs : AsyncCompletedEventArgs
       2 {
       3     public SomeTaskCompletedArgs(int result, Exception error, bool cancelled, object userState)
       4         : base(error, cancelled, userState)
       5     {
       6         _result = result;
       7     }
       8 
       9     public int result
      10     {
      11         get { return _result; }
      12     }
      13 
      14     int _result;
      15 }

                      另外,基于事件的異步模式常常提供了匯報(bào)進(jìn)度的事件。該事件的名稱常常由異步模式的實(shí)現(xiàn)類是否具有多個(gè)異步操作來決定。對(duì)于一個(gè)具有多個(gè)異步操作的實(shí)現(xiàn)類來說,函數(shù)SomeTaskAsync()所對(duì)應(yīng)的事件名應(yīng)為SomeTaskProgressChanged;而對(duì)于只有一個(gè)異步操作的實(shí)現(xiàn)類,該事件的名稱應(yīng)為ProgressChanged。這些事件所返回的ProgressChangedEventArgs帶有一個(gè)屬性ProgressPercentage,以允許用戶代碼根據(jù)當(dāng)前的進(jìn)度更新滾動(dòng)條等UI組成。

       

      異步模型的多調(diào)用

        異步模型中的另一個(gè)非常重要的概念就是多調(diào)用:異步操作的實(shí)現(xiàn)一般來說分為兩種方式:?jiǎn)握{(diào)用和多調(diào)用。單調(diào)用在當(dāng)前工作項(xiàng)沒有完成時(shí)不允許再次執(zhí)行,而多調(diào)用則允許多個(gè)工作項(xiàng)同時(shí)在后臺(tái)執(zhí)行。用戶代碼常常需要通過方法的簽名區(qū)分這兩種方式的函數(shù)異步操作:多調(diào)用接口常常提供了一個(gè)名為userState的額外參數(shù)。我們將在后面的章節(jié)中詳細(xì)介紹該參數(shù)。

        接下來要轉(zhuǎn)化的是函數(shù)的參數(shù)。異步函數(shù)的參數(shù)將根據(jù)其是否支持多調(diào)用而略有不同。如果一個(gè)異步函數(shù)僅僅是一個(gè)單調(diào)用函數(shù),那么該函數(shù)所使用的參數(shù)應(yīng)與相應(yīng)同步函數(shù)所使用的參數(shù)相同。如果異步函數(shù)支持多調(diào)用,那么該函數(shù)需要在相應(yīng)同步函數(shù)所使用的參數(shù)之后添加一個(gè)object類型的userState實(shí)例作為參數(shù)。例如對(duì)于同步函數(shù)SomeTask(string parameters),不支持多調(diào)用的異步函數(shù)應(yīng)為SomeTaskAsync(string parameters),而支持多調(diào)用的異步函數(shù)應(yīng)為SomeTaskAsync(string parameters, object userState)。

        該過程中較為例外的是out和ref參數(shù)。如果同步調(diào)用中包含一個(gè)out參數(shù),那么它將存在于表示返回值的組成中,如Complete事件中。而如果同步調(diào)用中包含一個(gè)ref參數(shù),那么它需要同時(shí)存在于異步函數(shù)的參數(shù)列表以及表示返回值的組成中。例如對(duì)于同步函數(shù)SomeTask(string parameters, out int result),轉(zhuǎn)化后的僅支持單調(diào)用的異步調(diào)用則為SomeTaskAsync(string parameters),同時(shí)Complete事件所傳回的參數(shù)將帶有參數(shù)result。同樣地,對(duì)于同步函數(shù)SomeTask(string parameters, ref int result),轉(zhuǎn)化后的支持單調(diào)用的異步調(diào)用應(yīng)為SomeTaskAsync(string parameters, int result),同時(shí)Complete事件所傳回的參數(shù)將帶有參數(shù)result。

        在介紹多調(diào)用和單調(diào)用時(shí),我們提到了參數(shù)userState。實(shí)際上,對(duì)參數(shù)userState的使用貫穿了整個(gè)基于事件的異步模型的實(shí)現(xiàn)中。從插入工作項(xiàng)到工作項(xiàng)完成,工作項(xiàng)取消以及工作項(xiàng)進(jìn)度更新,該參數(shù)都會(huì)附加在相應(yīng)的函數(shù)調(diào)用或事件參數(shù)中,從而允許模型的用戶代碼了解到底是哪個(gè)工作項(xiàng)發(fā)生了變化,即要求userState在整個(gè)異步模型的使用過程中是唯一的,能唯一標(biāo)明工作項(xiàng)。

        也正是由于這種唯一性要求,傳入多調(diào)用接口的userState對(duì)象需要用戶代碼自行生成。一般情況下,用戶需要自行提供對(duì)該參數(shù)的管理,如保證userState對(duì)象不會(huì)重復(fù)等等。而在模型的內(nèi)部實(shí)現(xiàn)中,您常常需要將userState對(duì)象添加到一個(gè)集合中。而在執(zhí)行完畢后,您需要從該集合中檢索該對(duì)象,執(zhí)行相應(yīng)的處理邏輯,并最終將其從集合中刪除。

        基于事件的異步模型常常需要執(zhí)行對(duì)異步函數(shù)所插入的工作項(xiàng)的取消,而執(zhí)行取消功能的函數(shù)則需要根據(jù)異步調(diào)用是否支持多調(diào)用以及表示異步模型的類型中是否僅有一個(gè)支持取消的異步操作。對(duì)于異步操作SomeTaskAsync(),取消工作項(xiàng)的各函數(shù)名將如下表所示:

       

      支持多調(diào)用

      不支持多調(diào)用

      類只包含一個(gè)異步操作

      void SomeTaskAsyncCancel(object userState)

      void SomeTaskAsyncCancel()

      類包含多個(gè)異步操作

      void AsyncCancel(object userState)

      void AsyncCancel()

        對(duì)于一個(gè)模型中所包含的多個(gè)異步函數(shù),您可以根據(jù)上表所列出的轉(zhuǎn)化方式依次執(zhí)行轉(zhuǎn)化。最終的轉(zhuǎn)化結(jié)果可能包含上表列出的兩個(gè)函數(shù)。例如對(duì)于模型中的支持多調(diào)用的函數(shù)TaskAsyncA()和不支持多調(diào)用的函數(shù)TaskAsyncB(),模型中將同時(shí)出現(xiàn)AsyncCancel(object userState)及AsyncCancel()兩個(gè)函數(shù)。

        從上面的列表中也可以看出,在類型包含多個(gè)異步操作并且支持多調(diào)用的函數(shù)的情況下,AsyncCancel()所傳入的userState參數(shù)應(yīng)能標(biāo)示出所有異步函數(shù)插入的工作項(xiàng),而不僅僅區(qū)分單個(gè)異步方法所產(chǎn)生的工作項(xiàng)。

       

      模型實(shí)現(xiàn)

        難道僅僅通過名稱就能得到異步執(zhí)行的功能?并不是這樣。為各組成指明命名規(guī)則僅僅會(huì)使代碼具有更為明顯的特征,使代碼具有更為明顯的特征,代碼更容易理解,減少出錯(cuò)可能,從而降低維護(hù)開銷。而實(shí)際的多線程功能則由其所實(shí)際包含的邏輯中。您可以使用您所熟悉的任何多線程編程方法。但是在本文中,我們將會(huì)向您介紹一個(gè)您可能并不熟悉的方法:使用AsyncManager。

        該類型提供了一個(gè)靜態(tài)成員函數(shù)CreateOperation()。其用來創(chuàng)建AsyncOperation類型的實(shí)例。擁有這樣一個(gè)特點(diǎn):通過調(diào)用該AsyncOperation類實(shí)例的Post()及PostOperationCompleted()函數(shù),您可以將委托調(diào)用轉(zhuǎn)發(fā)至創(chuàng)建AsyncOperation類型實(shí)例的線程中。也就是說,如果AsyncOperation類型實(shí)例是在A線程中創(chuàng)建的,卻被傳遞到B線程中,那么B線程中的執(zhí)行邏輯就可以通過 Post()以及PostOperationComplete()函數(shù)向A線程發(fā)送消息,以在A線程中執(zhí)行特定邏輯。

        現(xiàn)在我們就來看看該如何通過AsyncOperation來實(shí)現(xiàn)基于事件的異步模型,我們首先需要調(diào)用AsyncOperationManager的CreateOperation()函數(shù),并將該函數(shù)創(chuàng)建的AsyncOperation實(shí)例作為參數(shù)傳入異步調(diào)用中:

      1 private void BeginDownloadAsync(string link)
      2 {
      3     AsyncOperation operation = AsyncOperationManager.CreateOperation(link);
      4     RssDownloadWorkerHandler worker = new RssDownloadWorkerHandler(DownloadRss);
      5     worker.BeginInvoke(link, operation, null, null);
      6 }

        在上面的代碼中,link是需要下載的RSS的所在地址,而DownloadRss則是真正執(zhí)行執(zhí)行邏輯的函數(shù)。我們通過調(diào)用委托的BeginInvoke()函數(shù)在線程池中啟動(dòng)對(duì)該函數(shù)的執(zhí)行。而在委托所包裝的函數(shù)中,傳入異步調(diào)用的AsyncOperation實(shí)例將作為函數(shù)的參數(shù):

      1 private void DownloadRss(string link, AsyncOperation operation)…

        在這里,由于我們?cè)试S同時(shí)下載多個(gè)RSS源,因此使用多調(diào)用的異步模型是較為合適的。同時(shí),重復(fù)下載同一個(gè)地址所指向的RSS源是沒有必要的,因此BeginDownloadAsync()函數(shù)所傳入的參數(shù)link則相當(dāng)于userState參數(shù),用以區(qū)別各工作項(xiàng)。作為一個(gè)實(shí)現(xiàn)標(biāo)準(zhǔn),如果當(dāng)前下載項(xiàng)中已經(jīng)擁有了BeginDownloadAsync()函數(shù)所標(biāo)示的RSS地址,那么異步模型需要拋出一個(gè)表示下載項(xiàng)重復(fù)的ArgumentException類型的異常。這里需要注意的是,異常是線程相關(guān)的。為了能讓用戶代碼探測(cè)到該異常,我們應(yīng)在主線程中拋出異常。這也就迫使我們?cè)谥骶€程中管理當(dāng)前的工作項(xiàng)ID并執(zhí)行對(duì)多調(diào)用的檢查。

        反過來,如果異步模型需要將RSS的下載實(shí)現(xiàn)為單調(diào)用,那么在主線程中所需要執(zhí)行的檢查就需要是當(dāng)前是否擁有工作項(xiàng)沒有完成,并在當(dāng)前具有工作項(xiàng)的情況下拋出一個(gè)InvalidOperationException異常。同時(shí)我們還需要為模型添加IsBusy屬性,以用來提示用戶代碼是否可以插入下一個(gè)工作項(xiàng),從而避免多次插入工作項(xiàng)所導(dǎo)致的異常。

        接下來要討論的是如何實(shí)現(xiàn)異步模型的執(zhí)行邏輯。在編寫執(zhí)行邏輯的過程中,如果您希望觸發(fā)特定事件,那么您需要通過AsyncOperation的Post()或PostOperationCompleted()函數(shù)向原線程插入一個(gè)委托。這兩個(gè)函數(shù)都接受兩個(gè)參數(shù):第一個(gè)表示需要在AsyncOperation實(shí)例的創(chuàng)建線程上執(zhí)行的函數(shù),而第二個(gè)參數(shù)則表示需要傳遞給該函數(shù)的參數(shù)。就以DownloadRss()函數(shù)為例:

       1 private void DownloadRss(string link, AsyncOperation operation)
       2 {
       3     ……
       4     // 對(duì)OnProgressChangedInternal的執(zhí)行將從后臺(tái)線程轉(zhuǎn)至operation的創(chuàng)建線程中
       5     ProgressChangedEventArgs progressArgs = new ProgressChangedEventArgs(percentage);
       6     operation.Post(OnProgressChangedInternal, args);
       7 
       8     ……
       9     TaskCompleteEventArgs args = new TaskCompleteEventArgs(link, succeeded, source);
      10     operation.PostOperationCompleted(OnTaskCompleteInternal, args);
      11 }

        而在Post()和PostOperationComplete()函數(shù)所傳入的執(zhí)行函數(shù)則會(huì)運(yùn)行在創(chuàng)建AsyncOperation實(shí)例的線程中,兒不是當(dāng)前線程。因此在該傳入的函數(shù)中,您應(yīng)真正地發(fā)出事件。就以O(shè)nTaskCompleteInternal()為例:

      1 // 該函數(shù)在創(chuàng)建AsyncOperation實(shí)例的線程中執(zhí)行
      2 private void OnTaskCompleteInternal(object param)
      3 {
      4     TaskCompleteEventArgs args = param as TaskCompleteEventArgs;
      5 
      6     mTasks.Remove(args.Link);
      7     if (TaskComplete != null)
      8         TaskComplete(this, args); // 真正地引發(fā)事件
      9 }

        另一個(gè)需要考慮的操作就是工作項(xiàng)的取消。首先,您需要將工作項(xiàng)編寫為可取消的形式。在工作項(xiàng)執(zhí)行過程中,您需要一種方式,如標(biāo)志位等,通知工作項(xiàng)當(dāng)前任務(wù)應(yīng)當(dāng)取消,并在工作項(xiàng)自身執(zhí)行過程中對(duì)該標(biāo)志位進(jìn)行探測(cè)。同時(shí),在成功地取消了工作項(xiàng)的執(zhí)行之后,您需要發(fā)送相應(yīng)的Completed事件,并將其成員屬性Canceled設(shè)置為true,以區(qū)別真正的工作項(xiàng)完成所發(fā)出的Completed事件。

        同時(shí)您還需要理解爭(zhēng)用條件這一名詞。在異步模型執(zhí)行過程中,下載可能恰好在發(fā)送了工作項(xiàng)取消這一請(qǐng)求后完成了。在這種情況下,我們會(huì)認(rèn)為其成功完成,從而不再將AsyncCompletedEventArgs的Cancelled屬性設(shè)置為true。

       

      AsyncOperation內(nèi)部實(shí)現(xiàn)

        總的來說,對(duì)AsyncOperation的使用就是通過AsyncOperation實(shí)例保持對(duì)主線程的引用,并在需要從后臺(tái)線程向主線程中發(fā)送消息時(shí)向AsyncOpertation實(shí)例所記錄的主線程注冊(cè)回調(diào)邏輯。這種通過記錄創(chuàng)建線程來進(jìn)行線程管理的方法是在.net開發(fā)中非常常用的,也非常值得我們借鑒。經(jīng)過適當(dāng)簡(jiǎn)化后的相關(guān)代碼如下所示:

       1 public static class AsyncOperationManager
       2 {
       3     public static AsyncOperation CreateOperation(object userSuppliedState)
       4     {
       5         return AsyncOperation.CreateOperation(userSuppliedState, 
       6             SynchronizationContext.Current);
       7     }
       8     ……
       9 }
      10 
      11 public sealed class AsyncOperation
      12 {
      13     private AsyncOperation(object userSuppliedState, SynchronizationContext syncContext)
      14     {
      15         this.syncContext = syncContext;
      16     }
      17 
      18     public void Post(SendOrPostCallback d, object arg)
      19     {
      20         this.syncContext.Post(d, arg);
      21     }
      22     ……
      23 }

       

      總結(jié)

        最后來一點(diǎn)總結(jié)。在不了解基于事件的異步模型的眾多組成之前,我們并無法清晰地體會(huì)到其所具有的優(yōu)點(diǎn)。首先,基于事件的異步模型提供的是大家所最熟悉的事件/委托模型以及成員函數(shù),從而對(duì)用戶代碼而言是最自然也最容易接受的。另外,事件/委托模型可以將對(duì)多線程內(nèi)容的處理隱藏到模型的內(nèi)部,對(duì)多線程的處理局限于模型內(nèi)部,大大增強(qiáng)了代碼的可維護(hù)性。

       

      轉(zhuǎn)載請(qǐng)注明原文地址并標(biāo)明轉(zhuǎn)載:http://www.rzrgm.cn/loveis715/p/5250217.html

      商業(yè)轉(zhuǎn)載請(qǐng)事先與我聯(lián)系:silverfox715@sina.com

      公眾號(hào)一定幫忙別標(biāo)成原創(chuàng),因?yàn)閰f(xié)調(diào)起來太麻煩了。。。

       

      posted @ 2016-03-07 13:43  loveis715  閱讀(2346)  評(píng)論(1)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产午夜福利在线观看播放| 亚洲精品综合网二三区| 放荡的少妇2欧美版| 亚洲国产亚洲综合在线尤物| 国产精品视频不卡一区二区| 国产不卡一区在线视频| 无码综合天天久久综合网 | 国产日韩一区二区在线| 久久国产成人高清精品亚洲| 亚洲AV无码乱码在线观看性色扶 | 3d无码纯肉动漫在线观看| 久久久久国产精品人妻| 人妻精品久久无码区 | 国产一区在线播放av| 尤物国精品午夜福利视频| 白朗县| 好看的国产精品自拍视频| 免费国产一区二区不卡| 亚洲日韩性欧美中文字幕| 中文字幕99国产精品| 4399理论片午午伦夜理片| 在线看国产精品自拍内射| 国产一区精品综亚洲av| 国产免费一区二区三区在线观看| 国产av普通话对白国语| 亚洲成人av免费一区| 亚洲色婷婷综合久久| 老太脱裤子让老头玩xxxxx| 黑人好猛厉害爽受不了好大撑| 丰满人妻熟妇乱又仑精品| 精品日本免费一区二区三区| 欧美亚洲另类自拍偷在线拍 | 成全影视大全在线观看| 秋霞在线观看片无码免费不卡| 熟妇无码熟妇毛片| 亚洲永久精品免费在线看| 久久中文骚妇内射| 成人国产精品三上悠亚久久| 亚洲欧洲日产国码AV天堂偷窥 | 国产一区二区三区在线观| 熟女一区|