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);
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, static
, 方法
, public
, state
, 异步I/O
fs.write方法
c站、c语言、cf、ch、c罗,以便于您获取更多的相关知识。

时间: 2024-09-08 10:25:22

C#的异步文件操作的相关文章

C#的文件操作管理

文件管理是操作系统的一个重要组成部分,而文件操作就是对用户在编写应用程序时进行文件管理的一种手段. 目前有许多文件系统.在我们使用过的从Dos.Windows3.X.Windows95.WindowsNT.Windows2000这些操作系统中,用到了我们非常熟悉的FAT.FAT32.NTFS等文件系统.这些文件系统在操作系统内部实现时有不同的方式,然而它们提供给用户的接口是一致的.只要按照正规的方式来编写代码,而且程序不涉及到操作系统的具体特性,那么生成的应用程序就可以不经过改动,而在不同的操作

Mysql对文件操作的封装

mysql|封装 Mysql对文件操作的封装 在查看Mysql对文件的操作中发现,它在不同的操作系统上对文件的操作,除了使用标准C运行库函数,包括open.close.seek等,在Win32下的文件和目录操作函数使用了CreatFile.CloseHandl.SetFilePointer等,不明白为什么对文件的操作要封装出两套函数. 查看了相关资料,其实使用API和标准库函数都可以生成文本文件和二进制文件,在这点上没有区别.同read()对应的是ReadFile,同write()对应的是Wri

Mysql数据库对文件操作的封装

在查看Mysql对文件的操作中,它在不同的操作系统上对文件的操作,除了使用标准C运行库函数,包括open.close.seek等,在Win32下的文件和目录操作函数使用了CreatFile.CloseHandl.SetFilePointer等,很多人可能不明白为什么对文件的操作要封装出两套函数. 其实使用API和标准库函数都可以生成文本文件和二进制文件,在这点上没有区别.同read()对应的是ReadFile,同write()对应的是WriteFile,同seek()对应的是SetFilePoi

Android单元测试 - Sqlite、SharedPreference、Assets、文件操作 怎么测?

前言 上篇<Android单元测试 - 几个重要问题> 讲解了"何解决Android依赖.隔离Native方法.静态方法.RxJava异步转同步"这几个Presenter单元测试中常见问题.如果读者你消化得差不多,就接着看本篇吧. 在日常开发中,数据储存是必不可少的.例如,网络请求到数据,先存本地,下次打开页面,先从本地读取数据显示,再从服务器请求新数据.既然如此重要,对这块代码进行测试,也成为单元测试的重中之重了. 笔者在学会单元测试前,也像大多数人一样,写好了sql代码

Node.js文件操作一

Node.js和其他语言一样,也有文件操作.先不说node.js中的文件操作,其他语言的文件操作一般也都是有打开.关闭.读.写.文件信息.新建删除目录.删除文件.检测文件路径等.在node.js中也是一样,也都是这些功能,可能就是api与其他语言不太一样. 一.同步.异步打开关闭 /** * Created by Administrator on 2016/3/21. */ var fs=require("fs"); //同步读 fs.openSync = function(path,

Node.js本地文件操作之文件拷贝与目录遍历的方法_node.js

文件拷贝NodeJS 提供了基本的文件操作 API,但是像文件拷贝这种高级功能就没有提供,因此我们先拿文件拷贝程序练手.与 copy 命令类似,我们的程序需要能接受源文件路径与目标文件路径两个参数. 小文件拷贝我们使用 NodeJS 内置的 fs 模块简单实现这个程序如下. var fs = require('fs'); function copy(src, dst) { fs.writeFileSync(dst, fs.readFileSync(src)); } function main(a

PHP+iFrame实现页面无需刷新的异步文件上传_php技巧

本文实例讲述了PHP+iFrame实现页面无需刷新的异步文件上传,是非常实用的常见技巧.分享给大家供大家参考.具体分析如下: 说到iframe,现在用它的人是越来越少了,并且很多人都相信它应该被AJAX所取代,的确如此,因为AJAX太出色了. 不过有一种情况的实现我还是选择了iframe,这就是本文要说的文件的异步上传,感兴趣的可以试试,如果用原生的AJAX来实现应该是要复杂的多. 先来给初学者补补基础知识: 1. 在iframe标签一般会指定其name特性以于标识: 2. 在form表单中通过

Node.js文件操作二

前面的博客 Node.js文件操作一中主要是对文件的读写操作,其实还有文件这块还有一些其他操作. 一.验证文件path是否正确(系统是如下定义的) fs.exists = function(path, callback) { if (!nullCheck(path, cb)) return; var req = new FSReqWrap(); req.oncomplete = cb; binding.stat(pathModule._makeLong(path), req); function

nodejs文件操作模块FS(File System)常用函数简明总结_node.js

件系统操作相关的函数挺多的.首先可以分为两大类. 一类是异步+回调的. 一类是同步的. 在这里只对异步的进行整理,同步的只需要在函数名称后面加上Sync即可 1. 首先是一类最常规的读写函数,函数名称和形式,应该是起源于C语言的. 复制代码 代码如下: fs.open(文件路径,读写标识,[文件mode值,666],回调函数(err,文件句柄fd));          fs.read(文件句柄fd,被写入的buffer,offset,length,position,回调函数(err, byte