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

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

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

      上一次提到了如何跨線程訪問GUI。而這個需求往往是異步操作導致的。今天我們就來看看Jeffrey Richter寫的AsyncEnumerator如何幫助我們處理異步問題。

      先來看看最簡單的一段異步下載網頁的代碼:

          public class Program
      {
      private static WebRequest request;

      public static void Main(string[] args)
      {
      request
      = WebRequest.Create("http://www.thoughtworks.com.cn");
      request.BeginGetResponse(HandleResponse,
      null);
      Console.ReadLine();
      }

      private static void HandleResponse(IAsyncResult ar)
      {
      request.EndGetResponse(ar);
      Console.WriteLine(
      "Get response from web");
      }
      }

      很簡單不是嗎?如果我們下載之后還要異步存儲到本地的磁盤,這個時候就不是那么容易了:

      Code

      代碼太長了,以至于我不得不折疊起來。這段代碼還是有問題的,因為它沒有處理異常情況,中途出個錯,文件就不會被關閉。

      從邏輯上來說獲取Response,讀取Response流,寫入本地文件流從執行順序上來說是一個完成之后,然后過一會兒下個接上執行。理論上來講它就是

      HandleGetResponse(xxx);
      while(NotFinished(xxx)) {
      HandleReadResponseStream(xxx);
      HandleWriteFileStream(xxx);
      }
      CleanUp();

      但是我們不能這么寫。因為在每個操作之間都是一個異步等待的過程。實際上,是因為異步操作把一個完成的流程打散到了多個回調函數中去完成。那么有什么辦法可以讓一個方法執行一段,然后等一會,再執行一段呢?有,這就是yield。yield代表我暫時放棄執行的權利,等IO完成之后你再來執行我,我接著干下面的操作。

              private static void Demo()
      {
      int i = 1;
      foreach (var fib in Fib())
      {
      Console.WriteLine(i
      + ": " + fib);
      if (i++ > 10)
      {
      break;
      }
      }
      }

      private static IEnumerable<int> Fib()
      {
      int i = 1;
      int j = 1;
      yield return i;
      yield return j;
      while (true)
      {
      var k
      = i + j;
      yield return k;
      i
      = j;
      j
      = k;
      }
      }

      這個例子中,Fib(斐波那契額數列)是一個死循環。如果它是一個普通的函數,你是不能執行它的,因為它永遠不會放棄執行權,它會一只拽著CPU去算終極的fib。但是我們這個例子中的Fib不會。它在每次yield return的時候,都會跳出函數,返回到調用的地方。然后每次調用,都會從上次執行的地方繼續下去,繼續執行的時候所有的局部狀態(局部變量的值)都保留著上次的值。在foreach的背后是這么一個過程:

                  var enumerable = Fib();
      var enumerator
      = enumerable.GetEnumerator();
      enumerator.MoveNext();
      //Fib被執行 return i;
      Console.WriteLine(enumerator.Current);
      enumerator.MoveNext();
      //Fib被繼續執行 return j;
      Console.WriteLine(enumerator.Current);
      enumerator.MoveNext();
      //Fib被繼續執行 return i+j;
      Console.WriteLine(enumerator.Current);

       

      所以我們只要把上面的IO操作序列,稍微改寫就可以讓它們不四處散落了:

      BeginGetResponse(xxx);
      yield return 1;
      EndGetReponse(xxx);
      while(NotFinished(xxx)) {
      BeginReadResponseStream(xxx);
      yield return 1;
      EndGetResponseStream(xxx);
      BeginWriteFileStream(xxx);
      yield return 1;
      EndGetResponseStream(xxx);
      }
      CleanUp();

      因為每次yield return都會放棄執行權,所以我們可以在這個函數外的某處等待BeginXXX操作的回調,等IO操作完成了再來繼續執行這個函數。基于這個想法(最開始是這位仁兄想出來的http://msmvps.com/blogs/mihailik/archive/2005/12/26/79813.aspx),Jeffrey Richter寫了Power Threading庫(wintellect上的下載鏈接壞了,用這個http://www.wintellect.com/Downloads/PowerThreadingAttachments/Wintellect_Power_Threading_Library_(May_15,_2008).zip)。最后的代碼是這個樣子的:

       

              private static IEnumerator<int> Download(AsyncEnumerator ae)
      {
      var webRequest
      = WebRequest.Create("http://www.thoughtworks.com.cn");
      webRequest.BeginGetResponse(ae.End(),
      null);
      yield return 1;
      var response
      = webRequest.EndGetResponse(ae.DequeueAsyncResult());
      Console.WriteLine(
      "Get response from web");
      var buffer
      = new byte[4096];
      var count
      = buffer.Length;
      using (var responseStream = response.GetResponseStream())
      {
      using (var fileStream = new FileStream(@"c:\downloaded.html", FileMode.Create))
      {
      while (count > 0)
      {
      Console.WriteLine(
      "Read a chunk");
      responseStream.BeginRead(buffer,
      0, buffer.Length, ae.End(), null);
      yield return 1;
      count
      = responseStream.EndRead(ae.DequeueAsyncResult());
      Console.WriteLine(
      "Write a chunk");
      fileStream.BeginWrite(buffer,
      0, count, ae.End(), null);
      yield return 1;
      fileStream.EndWrite(ae.DequeueAsyncResult());
      }
      }
      }
      Console.WriteLine(
      "Finished downloading from response");
      }

      是不是很簡單呢?不過還有一個問題,那就是yield return我明白,是為了暫時退出這個函數,等待異步操作完成之后繼續執行。但是我不明白的是,為什么是yield return 1呢?

       

      其實這個yield return 1是給另外一個高級功能使用的。它的意思是“等待1個異步操作結束,然后執行我這行之后的代碼“。如果yield return 2,就是等待兩個異步操作。所以你必須先begin兩個異步操作,然后yield return 2去等待。AsyncEnumerator還有返回值等高級功能,并且AsycnEnumerator內部使用了上文提到的AsyncOperationManager,所以在你的代碼中可以安全地操作GUI不用害怕跨線程的問題。

      參考資料:

      Asynchronous iterators:

      http://msmvps.com/blogs/mihailik/archive/2005/12/26/79813.aspx

      Simplified APM With The AsyncEnumerator:

      http://msdn.microsoft.com/en-us/magazine/cc546608.aspx

      Simplified APM with C#:

      http://msdn.microsoft.com/en-us/magazine/cc163323.aspx

      More AsyncEnumerator Features:

      http://msdn.microsoft.com/en-us/magazine/cc721613.aspx

      Using C# 2.0 iterators to simplify writing asynchronous code:

      http://blogs.msdn.com/michen/archive/2006/03/30/using-c-2-0-iterators-to-simplify-writing-asynchronous-code.aspx

      http://blogs.msdn.com/michen/archive/2006/04/01/using-c-2-0-iterators-to-simplify-writing-asynchronous-code-part-2.aspx

      附記:

      喂,博主啊?為什么不直接創建一個新線程,然后在那里用同步操作完成上述動作?這個問題在我這里等價為什么要使用.NET的APM(Asynchronous Programming Model,異步編程模型)。正確的答案,參見http://msdn.microsoft.com/en-us/magazine/cc301191.aspx,Jeffrey Richter肯定寫過這個問題的答案。不那么正確的答案:

      1、提供如何實現異步操作的靈活性,新線程只是很多實現中的一種

      這樣我們可以利用Windows的Overlapped I/O,而這個就是一個內核級別的回調,不牽涉線程的問題了。性能直追epoll。

      2、提供了何時使用新線程的靈活性,在一開始創建一個新線程然后把所有代碼放到那里同步執行只是其中一種。

      一個很流行的idea,叫SEDA(Staged Event Driven Architecture),究其核心就是把長操作分解成為異步的短操作,然后用不同大小的Thread Pool來回調不同類型的異步操作,通過調優達到線程在stage之間的最佳配比。這樣避免了一有請求就起新線程的開銷,線程多了系統就響應不過來了。又避免了單線程異步回調的低資源利用率,特別是CPU已經多核了的情況下。利用APM和AsyncEnumerator,再加上自己實現的ThreadPool,做一個.NET版本的SEDA架構也是可能的。

      posted on 2008-11-03 22:11  taowen  閱讀(3152)  評論(4)    收藏  舉報
      主站蜘蛛池模板: 国产乱码精品一区二三区| 亚洲国产精品日韩AV专区| 国产综合久久久久鬼色| 香蕉亚洲欧洲在线一区| 一区二区三区四区自拍视频| 午夜毛片不卡免费观看视频| 特级做a爰片毛片免费看无码| 国产精品蜜臀av在线一区| 痉挛高潮喷水av无码免费 | 精品无码人妻| 亚洲熟妇av一区二区三区宅男| 日韩精品亚洲不卡一区二区| 国产欧美日韩精品丝袜高跟鞋| 欧洲一区二区中文字幕| 亚洲免费观看一区二区三区| 啊┅┅快┅┅用力啊岳网站| 久久久久久国产精品美女| 小鲜肉自慰网站xnxx| 一级女性全黄久久片免费| 日本少妇自慰免费完整版| 亚洲精品中文字幕一二三| 国产一区在线播放av| 亚洲欧洲精品日韩av| 亚洲第一二三区日韩国产| 成人免费在线播放av| 国产中文三级全黄| 久久99精品国产99久久6男男| 国产精品69人妻我爱绿帽子| 久久婷婷丁香五月综合五| 精品国产高清中文字幕| 男女一级国产片免费视频| 久久久这里只有精品10| 日本边添边摸边做边爱喷水| 精品黄色av一区二区三区| 坐盗市亚洲综合一二三区| 久久人人爽人人爽人人av| 中文字幕日韩国产精品| 亚洲乱码国产乱码精品精| 国产农村激情免费专区| 无码人妻一区二区三区精品视频| 民丰县|