C# 多线程文件读写整理总结

  • A+
所属分类:C#

C# 多线程文件读写整理总结 - DahlinSky的博客 - CSDN博客

C# 多线程文件读写整理总结

多线程读写文件一直是一个比较常用的技术,普通的锁显得效率低下,和单线程感觉基本没有啥区别,这里参考了大牛的代码,采用了线程池技术,小菜我一直不明白异步和多线程有啥区别,后来读了个大牛的博客,才明白,为加强理解,抄袭一下吧,

多线程相关名词概念的解释

  • 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。

其中两种并发关系分别是同步和互斥

- ***互斥***:进程间相互排斥的使用临界资源的现象,就叫互斥。
- ***同步***:进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。

其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。

  • 并行:在单处理器中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多处理器上的程序才可实现并行处理。从而可知,并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。
  • 多线程:多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。
  • 异步:异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。

异步和多线程并不是一个同等关系,异步是最终目的,多线程只是我们实现异步的一种手段。异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回而可以做其它的事情。实现异步可以采用多线程技术或则交给另外的进程来处理。

如果都是独占cpu 的业务, 比如举杠铃的业务, 在单核情况下 多线和单线 没有区别。
总结
1. 多线程的好处:比较容易的实现了异步切换的思想,
2. 多线程本身程还是以同步完成,但是应该说比效率是比不上异步的。
3. 多核的好处,就是可以同时做事情, 这个和单核完全不一样的。

线程池异步读写文件

废话不说了,直接上代码,很好理解的
class Program
{
  static void Main(string[] args)
  {
    //把线程池的最大值设置为1000
    ThreadPool.SetMaxThreads(1000, 1000);
    ThreadPoolMessage("Start");
    #region 异步写文件
    //新立文件temp.txt

FileStream stream0 = new FileStream("temp.txt", FileMode.OpenOrCreate,FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);

byte[] bytes = new byte[16384];
    string message = "An operating-system ThreadId...";
    bytes = Encoding.Unicode.GetBytes(message);
    //启动异步写入

stream0.BeginWrite(bytes, 0, (int)bytes.Length, new AsyncCallback(CallbackWrite), stream0);

stream0.Flush();
    #endregion
//----------------------------------------------------
    #region 异步读文件
    byte[] byteData = new byte[80961024];

FileStream stream1 = new FileStream("temp.txt", FileMode.OpenOrCreate,FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);

/把FileStream对象,byte[]对象,
      长度等有关数据绑定到FileData对象中,
      以附带属性方式送到回调函数
    
/
    FileData fileData = new FileData();
    fileData.Stream = stream1;
    fileData.Length = (int)stream1.Length;
    fileData.ByteData = byteData;
    //启动异步读取

stream1.BeginRead(byteData, 0, fileData.Length, new AsyncCallback(CallbackRead), fileData);

#endregion
    Console.ReadKey();
  }
/// 

/// 写文件的回调函数
/// 

///  static void CallbackWrite(IAsyncResult result)
{
   //显示线程池现状
   Thread.Sleep(200);
   ThreadPoolMessage("CallbackWrite");
   //结束异步写入
   FileStream stream = (FileStream)result.AsyncState;
   stream.EndWrite(result);
   stream.Close();
 }
 //显示线程池现状
 static void ThreadPoolMessage(string data)
 {
     int a, b;
     ThreadPool.GetAvailableThreads(out a, out b);

string message = string.Format("{0}\n  CurrentThreadId is {1}\n  " +"WorkerThreads is:{2}

CompletionPortThreads is :{3}",

data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());

Console.WriteLine(message);
 }
 public class FileData
 {
     public FileStream Stream;
     public int Length;
     public byte[] ByteData;
 }
 /// 

 /// 读文件的回调函数
 /// 

 ///   static void CallbackRead(IAsyncResult result)
 {
     ThreadPoolMessage("CallbackRead");
     //把AsyncResult.AsyncState转换为FileData对象,以FileStream.EndRead完成异步读取
     FileData fileData = (FileData)result.AsyncState;
     int length = fileData.Stream.EndRead(result);
     fileData.Stream.Close();
     //如果读取到的长度与输入长度不一致,则抛出异常
     if (length != fileData.Length)
         throw new Exception("Stream is not complete!");
string data = Encoding.ASCII.GetString(fileData.ByteData, 0, fileData.Length);
     Console.WriteLine(data.Substring(2, 22));
 }
}
-

多线程写文本文件

在网上发现了一个多线程写文本的帮助类,感觉不错,做个分享,感觉是利用了微软已经封装好的方法:
public virtual void Lock(long position, long length);
// 摘要:
// 防止其他进程更改 System.IO.FileStream。
// 参数:
// position:
// 要锁定的范围的开始处。此参数的值必须大于或等于零 (0)。
// length:
// 要锁定的范围。
// 异常:
// System.ArgumentOutOfRangeException:
// position 或 length 为负。
// System.ObjectDisposedException:
// 文件被关闭。
// System.IO.IOException:
//由于另一个进程已锁定文件的部分内容,因此该进程无法访问该文件。
[SecuritySafeCritical]
public virtual void Lock(long position, long length);
帮助类如下:
/// 

/// 多线程写文本文件
/// 

public class AsynFileHelp
{
 private static Dictionary lockDic = new Dictionary();
 private string fileName;
 /// 

 /// 获取或设置文件名称
 /// 

 public string FileName
 {
     get { return fileName; }
     set { fileName = value; }
 }
 /// 

 /// 构造函数
 /// 

 /// 每次开辟位数大小,这个直接影响到记录文件的效率  /// 文件全路径名  public AsynFileHelp(string filename)
 {
     fileName = filename;
 }
 /// 

 /// 创建文件
 /// 

 ///   public void Create(string fileName)
 {
     if (!File.Exists(fileName))
     {
         using (FileStream fs = File.Create(fileName))
         {
             fs.Close();
         }
     }
 }
 /// 

 /// 写入文本
 /// 

 /// 文本内容  private void Write(string content, string newLine)
 {
     if (string.IsNullOrEmpty(fileName))
     {
         throw new Exception("文件名不能为空!");
     }

using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 8, FileOptions.Asynchronous))

{

Byte[] dataArray = System.Text.Encoding.Default.GetBytes(content + newLine);

bool flag = true;
         long slen = dataArray.Length;
         long len = 0;
         while (flag)
         {
             try
             {
                 if (len >= fs.Length)
                 {
                     fs.Lock(len, slen);
                     lockDic[len] = slen;
                     flag = false;
                 }
                 else
                 {
                     len = fs.Length;
                 }
             }
             catch (Exception ex)
             {
                 while (!lockDic.ContainsKey(len))
                 {
                     len += lockDic[len];
                 }
             }
         }
         fs.Seek(len, SeekOrigin.Begin);
         fs.Write(dataArray, 0, dataArray.Length);
         fs.Close();
     }
 }
 /// 

 /// 写入文件内容
 /// 

 ///   public void WriteLine(string content)
 {
     this.Write(content, System.Environment.NewLine);
 }
 /// 

 /// 写入文件
 /// 

 ///   public void Write(string content)
 {
     this.Write(content, "");
 }
}
-

我使用过这个方法,挺好使的,这个方法只锁定了文本文件的部分行,所以其他线程还是可以访问该文件的,有兴趣的同学可以写个多线程测试程序,大量线程同时用该方法向同一文件中写数据,看看此方法能支持多少线程。

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin