C#线程学习笔记三:线程池中的I/O线程
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/20/MultiThreads.html,记录一下学习过程以备后续查用。
一、I/O线程实现对文件的异步
1.1 I/O线程介绍:
对于线程所执行的任务来说,可以把线程分为两种类型:工作者线程和I/O线程。
工作者线程用来完成一些计算的任务,在任务执行的过程中,需要CPU不间断地处理,所以,在工作者线程的执行过程中,CPU和线程的资源是充分利用的。
I/O线程主要用来完成输入和输出的工作,在这种情况下, 计算机需要I/O设备完成输入和输出的任务。在处理过程中,CPU是不需要参与处理过程的,此时正在运行的线程
将处于等待状态,只有等任务完成后才会有事可做, 这样就造成线程资源浪费的问题。为了解决这样的问题,可以通过线程池来解决这样的问题,让线程池来管理线程。
对于I/O线程,我们可以将输入输出操作分成三个步骤:启动、实际输入输出、处理结果。用于实际输入输出可由硬件完成,并不需要CPU的参与,而启动和处理结果也可以
不在同一个线程上,这样就可以充分利用线程资源。在.Net中通过以Begin开头的方法来完成启动,以End开头的方法来处理结果,这两个方法可以运行在不同的线程,这样我们
就实现了异步编程了。
1.2 .Net中如何使用异步
注意:
其实当我们调用Begin开头的方法,就是将一个I/O线程排入到线程池中(由.Net机制帮我们实现)。
注:工作者线程由线程池管理,直接调用ThreadPool.QueueUserWorkItem方法来将工作者线程排入到线程池中。
在.NET Framework中的FCL中有许多类型能够对异步操作提供支持,其中在FileStream类中就提供了对文件的异步操作的方法。
FileStream类要调用I/O线程要实现异步操作,首先要建立一个FileStream对象,然后通过下面的构造函数来初始化FileStream对象实现异步操作(异步读取和异步写入):
public FileStream (string path, FileMode mode, FileAccess access, FileShare share,int bufferSize,bool useAsync)
其中path代表文件的相对路径或绝对路径,mode代表如何打开或创建文件,access代表访问文件的方式,share代表文件如何由进程共享,buffersize代表缓冲区的大小,
useAsync代表使用异步I/O还是同步I/O,设置为true时,表示使用异步I/O。
下面代码演示异步写入文件:
class Program
{
static void Main(string[] args)
{
#region I/O线程:异步写入文件
const int maxSize = ;
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start."); //初始化FileStream对象
FileStream fileStream = new FileStream("Test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, , true); //打印文件流打开的方式
Console.WriteLine("Filestream is {0}opened with asynchronously.", fileStream.IsAsync ? "" : "not "); byte[] writeBytes = new byte[maxSize];
string writeMessage = "An operation use asynchronous method to write message......";
writeBytes = Encoding.Unicode.GetBytes(writeMessage);
Console.WriteLine("Message sizes is:{0} bytes.\n", writeBytes.Length);
//调用异步写入方法将信息写入到文件中
fileStream.BeginWrite(writeBytes, , writeBytes.Length, new AsyncCallback(EndWriteCallback), fileStream);
fileStream.Flush();
Console.Read();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 当数据写入文件完成后调用此方法来结束异步写操作
/// </summary>
/// <param name="asyncResult"></param>
private static void EndWriteCallback(IAsyncResult asyncResult)
{
Thread.Sleep();
PrintMessage("Asynchronous method start."); FileStream filestream = asyncResult.AsyncState as FileStream; //结束异步写入数据
filestream.EndWrite(asyncResult);
filestream.Close();
}
}
运行结果如下:

从运行结果可以看出,此时是调用线程池中的I/O线程去执行回调函数的,同时在项目的bin\Debug文件目录下生成了一个Test.txt文件。
下面代码演示异步读取文件:
class Program
{
//异步读取文件
const int maxSize = ;
private static readonly byte[] readBytes = new byte[maxSize]; static void Main(string[] args)
{
#region I/O线程:异步读取文件
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start."); // 初始化FileStream对象
FileStream fileStream = new FileStream("Test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, , false); // 异步读取文件内容
fileStream.BeginRead(readBytes, , readBytes.Length, new AsyncCallback(EndReadCallback), fileStream);
Console.Read();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 当数据读取文件完成后调用此方法来结束异步写操作
/// </summary>
/// <param name="asyncResult"></param>
private static void EndReadCallback(IAsyncResult asyncResult)
{
Thread.Sleep();
PrintMessage("Asynchronous method start."); // 把AsyncResult.AsyncState转换为State对象
FileStream readStream = (FileStream)asyncResult.AsyncState;
int readLength = readStream.EndRead(asyncResult);
if (readLength <= )
{
Console.WriteLine("Read error.");
return;
} string readMessage = Encoding.Unicode.GetString(readBytes, , readLength);
Console.WriteLine("Read message is :" + readMessage);
readStream.Close();
}
}
运行结果如下:

二、I/O线程实现对请求的异步
我们同样可以利用I/O线程来模拟浏览器对服务器请求的异步操作,在.NET类库中的WebRequest类提供了异步请求的支持。
下面代码演示异步请求:
class Program
{
static void Main(string[] args)
{
#region I/O线程:异步请求
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start."); // 发出一个异步Web请求
WebRequest webrequest = WebRequest.Create("https://www.cnblogs.com/");
webrequest.BeginGetResponse(ProcessWebResponse, webrequest); Console.Read();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// Web请求回调函数
/// </summary>
/// <param name="result"></param>
private static void ProcessWebResponse(IAsyncResult result)
{
Thread.Sleep();
PrintMessage("Asynchronous method start."); WebRequest webRequest = (WebRequest)result.AsyncState;
using (WebResponse wr = webRequest.EndGetResponse(result))
{
Console.WriteLine("Content length is : " + wr.ContentLength);
}
}
}
运行结果如下:

C#线程学习笔记三:线程池中的I/O线程的更多相关文章
- python 学习笔记(三)根据字典中值的大小对字典中的项排序
字典的元素是成键值对出现的,直接对字典使用sorted() 排序,它是根据字典的键的ASCII编码顺序进行排序,要想让字典根据值的大小来排序,可以有两种方法来实现: 一.利用zip函数将字典数据转化为 ...
- Linux进程线程学习笔记:运行新程序
Linux进程线程学习笔记:运行新程序 周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下 ...
- C#线程学习笔记二:线程池中的工作者线程
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/ThreadPool.html,记录一下学习过程以备后续查用. 一.线程池基础 首先,创 ...
- 转:专题三线程池中的I/O线程
上一篇文章主要介绍了如何利用线程池中的工作者线程来实现多线程,使多个线程可以并发地工作,从而高效率地使用系统资源.在这篇文章中将介绍如何用线程池中的I/O线程来执行I/O操作,希望对大家有所帮助. 目 ...
- C#线程学习笔记十:async & await入门三
一.Task.Yield Task.Yield简单来说就是创建时就已经完成的Task,或者说执行时间为0的Task,或者说是空任务,也就是在创建时就将Task的IsCompeted值设置为0. 我们知 ...
- C#线程学习笔记九:async & await入门二
一.异步方法返回类型 只能返回3种类型(void.Task和Task<T>). 1.1.void返回类型:调用方法执行异步方法,但又不需要做进一步的交互. class Program { ...
- C#线程学习笔记七:Task详细用法
一.Task类简介: Task类是在.NET Framework 4.0中提供的新功能,主要用于异步操作的控制.它比Thread和ThreadPool提供了更为强大的功能,并且更方便使用. Task和 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记
回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...
随机推荐
- 科学使用Log4View2
目录 目录 前言 科学使用 编辑和调试程序集 调试程序集 编辑程序集 结语 推荐文献 目录 NLog日志框架使用探究-1 NLog日志框架使用探究-2 科学使用Log4View2 前言 这个标题很低调 ...
- LinkedList实现原理(JDK1.8)
LinkedList实现原理(JDK1.8) LinkedList底层采用双向链表,如果对链表这种结构比较熟悉的话,那LinkedList的实现原理看明白就相当容易. 链表通过"指针&quo ...
- java path
static{ String path = new Object(){ public String getPath() { return this.getClass().getResource(&qu ...
- 【前端】之JavaScript基础知识
JS 基础知识 JS中,简单类型的数据存储在栈中,复杂类型的数据存储在堆中,其引用存储在栈中 JS中的深拷贝和浅拷贝: 浅拷贝:将对象中的所有简单类型的属性拷贝出来,引用类型属性直接赋值null 深拷 ...
- 05-kubernetes Pod控制器应用进阶
目录 Pod 资源 标签 给资源打标签 标签选择器 Pod 生命周期 实际操作 livenessProbe 实战 livenessProbe exec 测试 livenessProbe httpGet ...
- 格式化JS代码
平常在项目中经常会遇到下载别人的js文件都是加密过的,不方便阅读都是一整行, 个人无法进行阅读,浏览器能够识别出来,所以就可以使用浏览器进行格式化js代码: 1.打开浏览器chrome为例,打开使用j ...
- 【LiteOS】STM32F103-LiteOS移植教程(详细篇)
总览 本文基于STM32F103C8T6,详细讲述华为LiteOS的移植过程.开发工具是MDK5.LiteOS官方已经适配过cortex M系列内核的单片机,因此移植过程非常简单. LiteOS有两种 ...
- vue-socket.io使用教程与踩坑记录
全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/12018866.html,多谢,=.=~ (如果对你有帮助的话请帮我点个赞啦) 请先允许我狠狠吐个 ...
- BZOJ 1051: [HAOI2006]受欢迎的牛(SCC)
1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8172 Solved: 4470[Submit][Sta ...
- 洛谷 题解 P3385 【【模板】负环】
一.声明 在下面的描述中,未说明的情况下,\(N\) 是顶点数,\(M\)是边数. 二.判负环算法盘点 想到判负环,我们会想到很多的判负环算法.例如: 1. Bellman-Ford 判负环 这个算法 ...