程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#的異步文件操作

C#的異步文件操作

編輯:關於C#

先來說說同步和異步操作之間的主要區別。在同步I/O操作中,方法將一直處於等待狀態,直到I/O操作完成。而在異步I/O操作中,在開始了I/O操作後,程序的方法可以轉移去執行其它的操作,這樣大大提高了程序執行的效率。

由於Windows是一個多任務的操作系統,在同一時刻系統可能會接受到多個I/O操作請求,要求對磁盤文件執行各種操作。如果采用同步方式,那麼每時每刻最多只能有一個I/O操作在進行,而其它的任務都處於等待狀態,系統的利用率將會大為降低。異步I/O操作則較好地解決了這種性能上的問題。

Stream類支持在同一個流中既可以進行同步讀寫,也可以進行異步讀寫。Stream類是一個抽象類,它為我們提供了BeginRead、BeginWrite、EndReader、EndWrite、Read、Write、Seek等成員方法,協同完成對流的讀寫操作。所有這些方法都是虛方法。因此,在我們自己設計Stream類的派生類時,我們在類用於讀寫的成員方法Read和Write中應該重載這些方法,並同時設計它們同步和異步的執行代碼。BeginRead,EndRead,BeginWrite和EndWrite方法默認為我們提供的是異步讀寫操作方式,如果你的派生類的Read和Write方法執行同步操作時,那麼程序提供的效率不會很好。只有當它們執行異步操作時,我們才能有效地提高程序的執行效率。

Stream類還提供了ReadByte和WriteByte方法,用於一次讀寫方式,這時我們就需要編寫自己的方法來拋出一個異常。

下面的代碼是在.NET聯機幫助中提供的一個異步讀寫操作的例子,程序模擬了一個多處理器系統的工作。

程序清單17-8:

using System;
using System.IO;
using System.Threading;
using BenchUtil;
public class BulkImageProcAsync{
    public const String ImageBaseName="tmpImage-";
public const int numImages=200;
public const int numPixels=512*512;
    //ProcessImage has a simple O(N)loop,and we can vary the number
    //of times we repeat that loop to make the app more CPU-bound or more IO-bound.
public static int processImageRepeats=20;
   //Threads must decrement NumImagesToFinish,and protect
   //their access to it via a mutex.
   public static int NumImagesToFinish=numImages;
   public static Object NumImagesMutex=new Object[0];
   //WaitObject is signalled when all image processing is done.
   public static Object WaitObject=new Object[0];
   internal static PerfTimer Pf=new PerfTimer("Asynchronous Bulk Image Processor");
public class ImageStateObject{
       public byte[] pixels;
         public int imageNum;
}
public static void MakeImageFiles(){
 int sides=(int)Math.Sqrt(numPixels);
 Console.Write("Making"+numImages+""+sides+"x"+sides+"images... ");
   byte[] pixels=new byte[numPixels];
   for(int i=0;i<numPixels;i++)
  pixels[i]=(byte)i;
     for(int i=0;i<numImages;i++){
        FileStream fs=new FileStream(ImageBaseName+i+
          ".tmp",FileMode.Create,FileAccess.Write,FileShare.None,8192,false);
          fs.Write(pixes,0,pixels.Length);
     FlushFileBuffers(fs.GetHandle());
          fs.Close();
     }
      Console.WriteLine("Done.");
}
public static void ReadInImageCallback(IAsyncResult asyncResult){
ImageStateObject state=(ImageStateObject)asyncResult.AsyncState;
Console.WriteLine("Image"+state.imageNum+"was read.
"+(asyncResult.CompletedSynchronously?"synchronously":"asyncchronously"));
  Stream stream=(Stream)asyncResult.AsyncObject;
  int bytesRead=stream.EndRead(asyncResult);
  if(bytesRead!=numPixels)
    throw new Exception("In ReadInImageCallback,got wrong number of bytes
from the image! got:"+bytesRead);
  ProcessImages(state.pixels,state.imageNum);   stream.Close();
  //Now write out the image.
  //using async IO here probably swamps the threadpool,since
  //there are blocked threadpool threads on soon-to-be-//spawned
  //threadpool threads
  FileStream fs=new FileStream(ImageBaseName+state.imageNum+".done",
FileMode.Create,FileAccess.Write,FileShare.None,4096,false);
  fs.Write(state.pixels,0,numPixels);
  //IAsyncResult writeResult=fs.BeginWrtie(state.pixels,
  //0,numPixels,null,null);  //fs.EndWrite(writeResult);
  fs.Close();
  //Release memory as soon as possible,especially global state.
  state.pixels=null;  //Record that an image is done now.
  lock(NumImageMutex){   NumImagesToFinish--;
    if(NumImagesToFinish==0){
       Monitor.Enter(WaitObject);
       Monitor.Pulse(WaitObject);
       Monitor.Exit(WaitObject);
     }
  }
}
public static void ProcessImage(byte[] pixels,int imageNum){
 //Console.WriteLine("ProcessImage"+imageNum);
 //Do some CPU-intensive operation on the image.
 for(int i=0;i<processImageReports;i++)
    for(int j=0;j<numPixels;j++)
       pixels[j]+=1;
 //Console.WriteLine("ProcessImage"+imageNum+"done."); }
public static void ProcessImagesInBulk(){
  Console.WriteLine("Processing images...");
  //int timer=Pf.StartTimer("ProcessImages");
  int timer=Pf.StartTimer("Total Time");
  NumImagesToFinish=numImages;
  AsyncCallback readImagesCallback=new AsyncCallback(ReadInImageCallback);
  for(int i=0;i<numImages;i++){
    ImageStateObject state=new ImageStateObject();
      state.pixels=new byte[numPixels];
      state.imageNum=i;
    //Because very large items are read only once,the buffer
    //on the file stream can be very small to save memory.
  FileStream fs=new FileStream(ImageBaseName+i+".tmp",FileMode.Open,
FileAccess.Read,FileShare.Read,1,true);
  fs.BeginRead(state.pixels,0,numPixels,readImageCallback,state);
  } //Ensure all image processing is done.
  //If not,block until all are finished.
  bool mustBlock=false;
   lock(NumImagesMutex)
       if(NumImagesToFinish>0)
          mustBlock=true;
       }
       if(mustBlock){
       Console.WriteLine("All worker threads are queued...Blocking until they
complete. numLeft:"+NumImagesToFinish);
       Monitor.Enter(WaitObject); 
       Monitor.Wait(WaitObject);
       Monitor.Exit(WaitObject);
   }
    Pf.StopTimer(timer);
    Pf.OutputStoppedTime();
  }
  public static void Cleanup(){
      for(int i=0;i<numImages;i++){
         File.Delete(ImageBaseName+i+".tmp");
         File.Delete(ImageBaseName+i+".done");
     }
  }
  public static void TryToClearDiskCache(){
     //Try to force all pending writes to disk,AND to clear the
     //disk cache of any data.  byte[] bytes=new byte[100*(1<<20)];
     for(int i=0;i<bytes.Length;i++)  bytes[i]=0;
     bytes=null;  GC.Collect();  Thread.Sleep(2000); }
  public static void Main(String[] args){
     Console.WriteLine("Bulk image processing sample application,using asycn IO");
     Console.WriteLine("Simulates applying a simple transformation to "+numImages+"
\"imgaes\"");
     Console.WriteLine("ie,Async FileStream & Threadpool benchmark)");
     Console.Writeline("Warning - this test requires"+(numPixels*numImages*2)+"
bytes of tmp space");
     if(args.length==1){
        processImageRepeats=Int32.Parse(args[0]);
        Console.WriteLine("ProcessImage inner loop - "+processImageRepeats);
     }
     MakeImageFiles();
     TryToClearDiskCache();
         ProcessImageInBulk();
     Cleanup();
  }
  [dllimport("KERNEL32",SetlastError=true)]
  static extern void FlushFileBuffers(int handle);
}
這裡是采用同步方法實現同樣功能的程序。

程序清單17-9:

using System;
using System.IO;
using System.Threading;
using BenchUtil;
public class BulkImageProcSync
{
 public const String ImageBaseName="tmpImage-";
public const int numImages=200;
public const int numPixels=512*512;
 //ProcessImage has a simple O(N) loop,and we can vary the number
 //of times we repeat that loop to make the app more CPU-bound or more IO-bound.
public static int processImageRepeats=20;
internal static PerfTimer Pf=new PerfTimer("Synchronous Bulk Image Processor");
public static void MakeImageFiles(){
  int sides=(int)Math.Sqrt(numPixels);
  Console.Write("Making"+numImages+""+sides+"x"+sides+"images...  ");
  byte[] pixels=new byte[numPixels];
  for(int i=0;i<numPixels;i++)
    pixels[i]=(byte)i;
  for(int i=0;i<numImages;i++){
     FileStream fs=new FileStream(ImageBaseName+i+".tmp",FileMode.Create,
FileAccess.Write,FileShare.None,8192,false);
     fs.Write(pixels,0,pixels.Length);
     FlushFileBuffers(fs.GetHandle());   fs.Close();
    }
  Console.WriteLine("Done.");
  }
  public static void ProcessImage(byte[] pixels,int imageNum){
    //Console.WriteLine("ProcessImage"+imageNum);
    //Do some CPU-intensive operation on the image
    for(int i=0;i<processImageReports;i++)
       for(int j=0;j<numPixels;j++)
          pixels[j]+=1;
    //Console.WriteLine("processImage"+imageNum+"//done."); }
  public static void ProcessImagesInBulk(){
    Console.WriteLine("Processing images...");
    int timer=Pf.StartTimer("Total Time");
    byte[] pixels=new byte[numPixels];
    for(int i=0;i<numImages;i++){
       FileStream input=new FileStream(ImageBaseName+i+".tmp",
FileMode.Open,FileAccess.Read,FileShare.Read,4196,false);
       input.Read(pixels,0,numPixels);   input:Close();
      ProcessImage(pixels,i);
    FileStream output=new FileStream(ImageBaseName+i+
".done",FileMode.Create,FileAccess.Write,FileShare.None,4196,false);
   output.Write(pixels,0,numPixels);   output.Close();
   }
   Pf.StopTimer(timer);
   Pf.OutputStoppedTime();
 }
 public static void Cleanup()
 {
  for(int i=0;i<numImages;i++){
  File.Delete(ImageBaseName+i+".tmp");
  File.Delete(ImageBaseName+i+".done");
   }
 }

 public static void TryToClearDiskCache(){
   bute[] bytes=new byte[100*(1<<20)];
   for(int i=0;i<bytes.Length;i++)
       bytes[i]=0;
   bytes=null;
   GC.Collect();
   Thread.Sleep(2000);
  }
  public static void Main(String[] args){
    Console.WriteLine("Bulk image processing sample application,using synchronous
 IO");
    Console.WriteLine("Simulates applying a simple transformation to "+numImages+"
\"images\"");
  
    Console.WriteLine("ie,Sync FileStream benchmark)");
    Console.WriteLine("Warning - this test requires"+(numPixels*numImages*2)+"
bytes of tmp space");
    if(args.Length==1){
       processImageRepeats=Int32.Parse(args[0]);
       Console.WriteLine("ProcessImage inner loop -"+processImageRepeats);
    }
  MakeImageFiles();
  TryToClearDiskCache();
     ProcessImagesInBulk();
     Cleanup();
  }
  [dllimport"KERNEL32",SetlastError=true)]
  static extern void FlushFileBuffers(int handlw);
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved