亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C#:異步編程和線程的使用(.NET4.5)

2019-11-14 15:58:47
字體:
來源:轉載
供稿:網友

clip_image001

異步編程和線程處理是并發或并行編程非常重要的功能特征。為了實現異步編程,可使用線程也可以不用。將異步與線程同時講,將有助于我們更好的理解它們的特征。

本文中涉及關鍵知識點

1. 異步編程

2. 線程的使用

3. 基于任務的異步模式

4. 并行編程

5. 總結

  • 異步編程

什么是異步操作?異步操作是指某些操作能夠獨立運行,不依賴主流程或主其他處理流程。通常情況下,C#程序從Main方法開始,當Main方法返回時結束。所有的操作都是按順序執行的。執行操作是有序列的,一個操作必須等到其前面的操作完成才能夠執行。如以下代碼示例:

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  DoTaskOne();
   6:   
   7:  DoTaskTwo();
   8:   
   9:  }

“DoTaskOne”方法結束后,DoTaskTwo()才能夠執行。

異步編程中常用后臺運行的方法體現,主調用線程不會被阻塞。調用后臺運行的方法后,執行流程會立即返回到調用的線程并繼續執行其他任務。后臺運行方法通常是用線程或任務來實現。

在上面的例子中,在“DoTaskOne”方法調用成功后,如果“DoTaskOne”是異步調用,,執行流程立即返回到Main方法中,并繼續執行“DoTaskTwo” 方法。

C#提供了Thread類創建線程實現異步編程,或者使用.NET提供的異步模式實現異步編程。.NET中提供了三種不同的異步模式:

1. 異步編程模型(APM)模式

2. 基于事件的異步模式(EAP)

3. 基于任務的異步模式(TAP)

前兩種模型微軟官方并不推薦使用,本文不再詳細描述。我們將詳細討論基于任務的異步模式(TAP):

  • 線程的使用

在.NET 4.5中引入了異步編程模式,大部分情況下都不需要我們手動創建線程。編譯器已經替代了開發人員來完成這項工作。

創建新線程是非常耗時的。一般情況下,異步和并行編程使用 “基于任務的異步模式(TAP)”和“任務并行庫(TPL)”就夠了。如果需要控制線程的功能則需要使用其他模式。

TAP和TPL都是基于任務。一般來說任務是從線程池中調用線程( 線程池.NET框架創建的和維護的線程集。如果我們使用任務,就不需要直接調用線程池。

任務可以在以下情況運行:

1. 在正在運行的線程中

2. 在新線程中

3. 從線程池中的某一線程中

4. 沒有線程也可以運行

如果使用任務機制,開發人員就不必擔心線程的創建或使用,.NET框架已經為我們解決了這一難題。

有時候需要控制線程,執行以下操作:

1. 設置線程名稱

2. 設置線程優先級

3. 設置線程是前端或后端運行

我們可以使用線程類來創建線程。

使用Thread類創建線程

Thread類的構造函數接收委托類型的參數

1. ThreadStart:定義了返回值為空的方法,且不帶參數的方法。

2. ParameterizedThreadStart:定義了返回值為空且有一個object類型的參數。

下面是一個簡單的例子,使用 Start方法啟動一個新線程:

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  Thread thread = new Thread(DoTask);
   6:   
   7:  thread.Start();// Start DoTask method in a new thread
   8:   
   9:  //Do other tasks in main thread
  10:   
  11:  }
  12:   
  13:  static public void DoTask() {
  14:   
  15:  //do something in a new thread 
  16:   
  17:  }

可以用Lamda表達式代替線程名稱:

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  Thread thread = new Thread(() => {
   6:   
   7:  //do something in a new thread
   8:   
   9:  });
  10:   
  11:  thread.Start();// Start a new thread
  12:   
  13:  //Do other tasks in main thread
  14:   
  15:  }

如果不需要引用變量,可如下直接啟動線程:

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  new Thread(() => {
   6:   
   7:  //do something in a new thread
   8:   
   9:  }).Start();// Start a new thread
  10:   
  11:  //Do other tasks in main thread
  12:   
  13:  }

但是,如果想控制線程對象,對線程設置一些屬性,需要在線程創建后引用線程變量。如下可給線程對象的不同屬性設值:

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  Thread thread = new Thread(DoTask);
   6:   
   7:  thread.Name = "My new thread";// Asigning name to the thread
   8:   
   9:  thread.IsBackground = false;// Made the thread forground
  10:   
  11:  thread.PRiority = ThreadPriority.AboveNormal;// Setting thread priority
  12:   
  13:  thread.Start();// Start DoTask method in a new thread
  14:   
  15:  //Do other task in main thread
  16:   
  17:  }

調用引用變量,可以執行一些操作如中止線程或通過調用join方法等待阻塞線程。

如果需要通過函數傳值,可以給Start方法傳值。由于該方法的參數為Object類型,因此需要強制轉換類型。

   1:  static void Main(string[] args)
   2:   
   3:  {
   4:   
   5:  Thread thread = new Thread(DoTaskWithParm);
   6:   
   7:  thread.Start("Passing string");// Start DoTaskWithParm method in a new thread
   8:   
   9:  //Do other task in main thread
  10:   
  11:  }
  12:   
  13:  static public void DoTaskWithParm(object data)
  14:   
  15:  {
  16:   
  17:  //we need to cast the data to appropriate object
  18:   
  19:  }

“async”和“await”關鍵字

.NET框架引入了兩個新的關鍵字來實現異步編程:“async”和“await”。使用 “await”的異步方法必須由“async”修飾符來聲明方法。“await”關鍵字修飾調用異步方法。await 運算符應用于一個異步方法中的任務以掛起該方法的執行,直到等待任務完成.如下: 

   1:  private async static void CallerWithAsync()// async modifier is used 
   2:   
   3:  { 
   4:   
   5:  string result = await GetSomethingAsync();// await is used before a method call. It suspends
   6:     //execution of CallerWithAsync() method and control returs to the calling thread that can 
          //perform other task. 
   7:   
   8:  Console.WriteLine(result);
   9:     // this line would not be executed before GetSomethingAsync() //method completes 
  10:   
  11:  } 

而“ async ”修飾符只能用于返回值為Task類型或Void的方法。它不能用于主程序的切入點。

所有的方法之前不能使用await關鍵字,使用“await”關鍵字方法必須返回 “可等待”類型。以下屬于“可等待”類型:

1. Task

2. Task<T>

3. 自定義“可等待”類型。

  • 基于任務的異步模式

首先我們需要聲明一個返回類型為Task或Task<T>的異步方法??梢酝ㄟ^以下幾種方式創建任務:

1. Task.Factory.StartNew方法:在之前的.NET版本(在.NET 4中),是創建和啟動任務的主要方法。

2. Task.Run或Task.Run <T>方法:從.NET 4.5這個方法已經被使用。此方法足以滿足常見情況。

3. Task.FromResult方法:如果結果是已計算,就可以用這個方法來創建任務。

創建并等待一個任務

使用Task.Run <T>方法創建Task。該方法將特定工作按順序排列在線程池中運行,并返回工作的任務句柄。需要以下步驟從同步方法中創建異步任務:

1. 假設下面方法是同步的,但需要一定的時間來完成:

   1:  static string Greeting(string name) 
   2:   
   3:  { 
   4:   
   5:  Thread.Sleep(3000); 
   6:   
   7:  return string.Format("Hello, {0}", name); 
   8:   
   9:  } 

2. 要以異步方式訪問此方法,必須以異步方式封裝。命名為“GreetingAsync”。增加“Async”的后綴命名異步方法。

 

   1:  static Task<string> GreetingAsync(string name) 
   2:   
   3:  { 
   4:   
   5:  return Task.Run<string>(() => 
   6:   
   7:  { 
   8:   
   9:  return Greeting(name); 
  10:   
  11:  }); 
  12:   
  13:  } 

3.現在,可通過使用的await關鍵字調用異步方法GreetingAsync

 

   1:  private async static void CallWithAsync() 
   2:   
   3:  { 
   4:   
   5:  //some other tasks 
   6:   
   7:  string result = await GreetingAsync("Bulbul"); 
   8:   
   9:  //We can add multiple “await” in same “async” method 
  10:   
  11:  //string result1 = await GreetingAsync(“Ahmed”); 
  12:   
  13:  //string result2 = await GreetingAsync(“Every Body”); 
  14:   
  15:  Console.WriteLine(result); 
  16:   
  17:  } 

當“CallWithAsync”方法被調用時,與常規的同步方法一樣執行,直到遇到“await”的關鍵字。當它執行到 await的關鍵字會處理執行,并開始等待“GreetingAsync(” Bulbul “)” 方法被完成。同時,程序流將返回” CallWithAsync “方法的調用者,并繼續執行調用者的任務。

當“GreetingAsync(" Bulbul ") 方法完成,“CallWithAsync”的方法恢復 “await關鍵字后的其他任務。在本實例中,將繼續執行的代碼“Console.WriteLine(result)”

4. 使用任務持續:Task類 “ContinueWith”的方法定義了Task完成后被調用的代碼。

   1:  private static void CallWithContinuationTask() 
   2:   
   3:  { 
   4:   
   5:  Task<string> t1 = GreetingAsync("Bulbul"); 
   6:   
   7:  t1.ContinueWith(t => 
   8:   
   9:  { 
  10:   
  11:  string result = t.Result; 
  12:   
  13:  Console.WriteLine(result); 
  14:   
  15:  }); 
  16:   
  17:  } 

如果使用“ContinueWith”的方法就不需要使用“await“關鍵字,編譯器會自動在合適的位置中添加“await”關鍵字。

等候多??個異步方法。

看看下面的代碼:

   1:  private async static void CallWithAsync() 
   2:   
   3:  { 
   4:   
   5:  string result = await GreetingAsync("Bulbul"); 
   6:   
   7:  string result1 = await GreetingAsync(&ldquo;Ahmed&rdquo;); 
   8:   
   9:  Console.WriteLine(result); 
  10:   
  11:  Console.WriteLine(result1); 
  12:   
  13:  }

有兩個正在等待調用函數序列。“GreetingAsync(” Ahmed “)” 會在完成第一個呼叫“GreetingAsync(” Bulbul “)” 之后啟動。如果“result”和上面的代碼“result1”是獨立的,那么連續的“awiating”并不是一個好的做法。

在這種情況下,我們可以簡化調用方法,不需要添加多個“await”關鍵字,只在一個地方添加await關鍵字,如下所示,這種情況下,該方法的調用都可以并行執行。

   1:  private async static void MultipleAsyncMethodsWithCombinators() 
   2:   
   3:  { 
   4:   
   5:  Task<string> t1 = GreetingAsync("Bulbul"); 
   6:   
   7:  Task<string> t2 = GreetingAsync("Ahmed"); 
   8:   
   9:  await Task.WhenAll(t1, t2); 
  10:   
  11:  Console.WriteLine("Finished both methods./n " + 
  12:   
  13:  "Result 1: {0}/n Result 2: {1}", t1.Result, t2.Result); 
  14:   
  15:  } 

在這里,我們使用Task.WhenAll連接器。Task.WhenAll創建一個任務,將完成所有的提供的任務。Task類也有其他的結合器。Task.WhenAny,當所任務鏈中所有的任務完成時,結束使用。

處理異常

必須把“await的代碼塊放在try塊內捕獲異常。

   1:  private async static void CallWithAsync() 
   2:   
   3:  { 
   4:   
   5:  try 
   6:   
   7:  { 
   8:   
   9:  string result = await GreetingAsync("Bulbul"); 
  10:   
  11:  } 
  12:   
  13:  catch (Exception ex) 
  14:   
  15:  { 
  16:   
  17:  Console.WriteLine(&ldquo;handled {0}&rdquo;, ex.Message); 
  18:   
  19:  } 
  20:   
  21:  } 

如果try塊中有多個“await”,只有第一個” await“異常會被處理,其他“await”將無法被捕捉。如果希望所有的方法都能捕獲異常,不能使用“await”關鍵字調用方法,使用Task.WhenAll來執行任務。

   1:  private async static void CallWithAsync() 
   2:   
   3:  { 
   4:   
   5:  try 
   6:   
   7:  { 
   8:   
   9:  Task<string> t1 = GreetingAsync("Bulbul"); 
  10:   
  11:  Task<string> t2 = GreetingAsync("Ahmed"); 
  12:   
  13:  await Task.WhenAll(t1, t2); 
  14:   
  15:  } 
  16:   
  17:  catch (Exception ex) 
  18:   
  19:  { 
  20:   
  21:  Console.WriteLine(&ldquo;handled {0}&rdquo;, ex.Message); 
  22:   
  23:  } 
  24:   
  25:  } 

捕獲所有任務的錯誤一種方法是在try塊之外聲明任務,這樣可以從try塊進行訪問,并檢查任務的“IsFaulted”屬性。如果它存在異常那么“IsFaulted”屬性值為True,就可捕獲任務實例的內部異常。

還有另一個更好的辦法:

   1:  static async void ShowAggregatedException() 
   2:   
   3:  { 
   4:   
   5:  Task taskResult = null; 
   6:   
   7:  try 
   8:   
   9:  { 
  10:  Task<string> t1 = GreetingAsync("Bulbul"); 
  11:   
  12:  Task<string> t2 = GreetingAsync("Ahmed"); 
  13:   
  14:  await (taskResult = Task.WhenAll(t1, t2)); 
  15:   
  16:  } 
  17:   
  18:  catch (Exception ex) 
  19:   
  20:  { 
  21:   
  22:  Console.WriteLine("handled {0}", ex.Message); 
  23:   
  24:  foreach (var innerEx in taskResult.Exception.InnerExceptions) 
  25:   
  26:  { 
  27:  Console.WriteLine("inner exception {0}", nnerEx.Message); }
  28:  } 
  29:   
  30:  } 

取消任務

在此之前,如果從線程池中調用線程,線程是不可能取消?,F在,Task類提供了一個方法基于CancellationTokenSource類能夠取消已啟動的任務,取消任務步驟:

1. 異步方法應該除外 “ CancellationToken” 參數類型

2. 創建CancellationTokenSource類實例:

    var cts =new CancellationTokenSource();

3. 傳遞CancellationToken,如:

   1:    Task<string> t1 = GreetingAsync("Bulbul", cts.Token);

4. 長時間運行的方法中,必須調用CancellationToken ThrowIfCancellationRequested()方法

 

   1:   static string Greeting(string name, CancellationToken token){ 
   2:   
   3:  Thread.Sleep(3000); 
   4:   
   5:  token. ThrowIfCancellationRequested(); 
   6:   
   7:  return string.Format("Hello, {0}", name); 
   8:   
   9:  } 


5. 從等待的Task中捕獲 OperationCanceledException異常。

 6. 如果通過調用CancellationTokenSource的實例的方法執行取消操作,將從長時間運行操作中拋出OperationCanceledException異常。也可以設置取消的時間。以下是完整的代碼,一秒后執行取消操作:

   1:   static void Main(string[] args) 
   2:   
   3:   { 
   4:   CallWithAsync(); 
   5:   
   6:  Console.ReadKey(); 
   7:   
   8:   } 
   9:   
  10:   
  11:  async static void CallWithAsync() 
  12:   
  13:  { 
  14:   
  15:  try 
  16:   
  17:   { 
  18:   
  19:  CancellationTokenSource source = new CancellationTokenSource(); 
  20:   
  21:  source.CancelAfter(TimeSpan.FromSeconds(1)); 
  22:   
  23:   var t1 = await GreetingAsync("Bulbul", source.Token); 
  24:   } 
  25:   
  26:   catch (OperationCanceledException ex) 
  27:   
  28:  { 
  29:   
  30:   Console.WriteLine(ex.Message); 
  31:   
  32:   } 
  33:   
  34:   } 
  35:   
  36:  static Task<string> GreetingAsync(string name, CancellationToken token) 
  37:   
  38:   { 
  39:   
  40:   return Task.Run<string>(() => 
  41:   
  42:   { 
  43:   
  44:   return Greeting(name, token); 
  45:   
  46:   }); 
  47:  } 
  48:   
  49:   
  50:   static string Greeting(string name, CancellationToken token) 
  51:   
  52:   { 
  53:   
  54:  Thread.Sleep(3000); 
  55:   token.ThrowIfCancellationRequested(); 
  56:   
  57:   return string.Format("Hello, {0}", name); 
  58:   
  59:   } 
  60:   
  • 并行編程

.NET 4.5及以上版本推出“Parallel類,是線程類的抽象。使用“Parallel”類,我們可以實現并行。并行與線程不同,它使用所有可用的CPU或內核的。以下兩種類型的并行是可行:

  1. 數據并行:如果我們有數據的大集合,我們希望在每個數據的某些操作進行并行使用,那么就可以使用數據并行。Parallel類有靜態For或ForEach來執行數據并行行,如
   1:  ParallelLoopResult result =
   2:                      Parallel.For(0, 100, async (int i) =>
   3:                      {
   4:                          Console.WriteLine("{0}, task: {1}, thread: {2}", i,
   5:                          Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
   6:                          await Task.Delay(10);
   7:                         
   8:                });
      

For或ForEach方法可以在多線程中和且索引無序可以是無序的。

如果想停止并行For或ForEach方法,可通過ParallelLoopState作為參數,并根據需要打破循環的狀態,跳出循環。

   1:  ParallelLoopResult result =
   2:                      Parallel.For(0, 100, async (int i, ParallelLoopState pls) =>
   3:                      {
   4:                          Console.WriteLine("{0}, task: {1}, thread: {2}", i,
   5:                          Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
   6:                          await Task.Delay(10);
   7:                          if (i > 5) pls.Break();
   8:                });

     2. 任務并行:如果想要同時運行多個任務的,我們可以通過調用Parallel類的invoke方法使用任務并行Parallel.Invoke方法接收委托行為的數組。例如:

   1:  static void ParallelInvoke() 
   2:   
   3:  { 
   4:   
   5:  Parallel.Invoke(MethodOne, MethodTwo); 
   6:   
   7:  } 
   8:   
  • 結論

本文詳細介紹了.NET Framework 4.5提供的異步編程技術及細節。

原文鏈接:http://www.codeproject.com/Articles/996857/Asynchronous-programming-and-Threading-in-Csharp-N


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
午夜欧美大片免费观看| 日韩中文字幕免费| 91精品91久久久久久| 国产成人jvid在线播放| 岛国视频午夜一区免费在线观看| 热久久免费国产视频| 91成人免费观看网站| 9.1国产丝袜在线观看| 欧美日韩免费区域视频在线观看| 日韩av一卡二卡| 最近中文字幕mv在线一区二区三区四区| 精品日韩中文字幕| 国产精品第一页在线| 国产精品福利片| 亚洲性av网站| 亚洲成年人在线播放| 在线观看国产精品91| 久久久国产精品亚洲一区| 久久精品久久精品亚洲人| 亚洲午夜女主播在线直播| 亚洲性69xxxbbb| 69国产精品成人在线播放| 亚洲欧美一区二区三区在线| 成人激情视频在线观看| 日韩av网站在线| 久久99青青精品免费观看| 91亚洲精品在线| 国产区精品视频| 日本精品视频在线| 精品无人区太爽高潮在线播放| 精品国产视频在线| 欧美夜福利tv在线| 亚洲精品美女在线观看| 精品国产拍在线观看| 中文字幕亚洲精品| 亚洲福利在线观看| 好吊成人免视频| 久久精品在线视频| 91九色综合久久| 国内免费精品永久在线视频| 欧美精品18videos性欧| 亚洲欧洲日韩国产| 久久精品国产视频| 日韩精品视频免费专区在线播放| 亚洲欧美日韩图片| 91精品视频在线播放| 欧美日韩国产精品一区| 国产精品久久久久久av下载红粉| 欧美激情精品久久久久久大尺度| 亚洲一区免费网站| 国产成人久久精品| 国产精品欧美激情在线播放| 欧美成人性色生活仑片| 久久精品成人动漫| 国产精品第8页| 一区二区av在线| 久久福利视频导航| 国产精品久久精品| 久久久av亚洲男天堂| 久久亚洲精品中文字幕冲田杏梨| 丁香五六月婷婷久久激情| 亚洲欧洲午夜一线一品| 992tv在线成人免费观看| 欧美精品一本久久男人的天堂| 国产ts人妖一区二区三区| 亚洲色无码播放| 国产成人黄色av| 午夜剧场成人观在线视频免费观看| 国产手机视频精品| 色噜噜狠狠狠综合曰曰曰| 亚洲成人久久网| 国产综合视频在线观看| 日韩中文理论片| 青草青草久热精品视频在线观看| 亚洲在线观看视频网站| 国产精品视频自在线| 91欧美精品午夜性色福利在线| 国产精品美女主播| 国产亚洲欧美一区| 性金发美女69hd大尺寸| 日韩av电影在线免费播放| 亚洲国内精品在线| 国产不卡av在线免费观看| 欧美高清在线视频观看不卡| 国产精品18久久久久久首页狼| 亚洲国产另类 国产精品国产免费| 丁香五六月婷婷久久激情| 国产成人精品在线播放| 欧美精品国产精品日韩精品| 久久99久久99精品免观看粉嫩| 亚洲一区二区在线| 欧美成人在线网站| 国产精品偷伦视频免费观看国产| 精品福利免费观看| 日韩精品在线观看一区二区| 亚洲成人网在线观看| 久久久精品久久久| 国产一区视频在线| 欧美性猛交xxxx乱大交3| 国产精品av免费在线观看| 国产精品美女免费看| 欧美成人激情视频免费观看| 亚洲美女中文字幕| 日韩电影中文 亚洲精品乱码| 精品亚洲一区二区三区在线观看| 亚洲伊人久久大香线蕉av| 亚洲国产毛片完整版| 国产精品久久久久久久久免费| 成人福利在线观看| 日韩视频免费看| 色视频www在线播放国产成人| 国产精品久久99久久| 91精品久久久久久久久青青| 欧美成人精品激情在线观看| 日韩av手机在线| 欧美激情在线有限公司| 亚洲欧美一区二区三区四区| 亚洲深夜福利视频| 国产suv精品一区二区三区88区| 欧美国产亚洲视频| 亚洲欧美变态国产另类| 2019国产精品自在线拍国产不卡| 国产亚洲视频中文字幕视频| 91在线精品播放| 亚洲自拍小视频| 亚洲成人中文字幕| 亚洲免费av电影| 日韩hd视频在线观看| 国产一区深夜福利| 亚洲va男人天堂| 91麻豆桃色免费看| 亚洲人成网站在线播| 95av在线视频| 精品国产一区二区三区久久久狼| 国产精品18久久久久久麻辣| 国产原创欧美精品| 国产亚洲精品一区二区| 国模私拍视频一区| 亚洲欧美成人一区二区在线电影| 日韩欧美国产激情| 国产精品www| 日韩精品高清在线| 国产成人jvid在线播放| 亚州欧美日韩中文视频| 国产成人在线视频| 午夜免费日韩视频| 国产69久久精品成人看| 欧美极品少妇xxxxⅹ裸体艺术| 欧美电影免费在线观看| 日韩在线视频观看| 在线日韩中文字幕| 欧美日韩在线影院| 欧美影院久久久| 亚洲一区二区免费| www.日韩.com| 欧美极度另类性三渗透| 日韩电影免费观看在线| 91精品久久久久久久久中文字幕| 这里只有精品在线播放| 国产精品亚洲аv天堂网| 国产一区二区三区在线观看网站| 日韩欧美中文免费| 538国产精品一区二区在线| 久久精品国产一区|