[试验一] WebRequest
参考链接
.Net在每个进程中设置一个ThreadPool, 此ThreadPool中有两种类型的线程:CLR worker threads和completionPortThreads;或者说.Net在一个进程中维护着2个线程池,一个同步线程池(CLR worker threads pool),一个异步IO线程池(completionPortThreads pool). 从类库的方法看,也确实做了区分:
但两者并不是桥归桥路归路互不影响的。
结果显示WebRequest使用了一个IO线程,两者似乎互不影响。
但把异步调用的代码放到循环后面,就会出现“ThreadPool 中没有足够的自由线程来完成该操作” 错误. 通过 查阅一些资料,了解到在 BeginGetResponse 的最后有一个IsThreadPoolLow 判断来查询池中有多少个可用工作线程。如果数量过少(少于 2 个),将会引发 InvalidOperationException。
通过把MaxThread分别设置为1或2,直接运行WebRequest异步调用可以证实。
结论:虽然确实有CLR线程和IO线程之分,但CLR线程池还是可能影响异步IO操作,要根据具体的实现。
[试验2] FileStream
既然 CLR线程池能影响异步IO,再通过一个实现来尝试猜测下具体的联系。
运行结果显示 FileStream的异步操作不会受CLR线程耗尽的影响,自己会调用一个IO线程。 同时, 与WebRequest实现不同, FileStream的异步操作实现不会做IsThreadPoolLow 判断,因此这里的For循环代码段与异步读文件代码段的顺序可以互换。
![](http://hi.csdn.net/attachment/201112/1/0_1322729979iI9m.gif)
当把缓冲区的大小设置的比byte[]大时,一个有趣的情况发生了
结果显示异步读操作使用了一个同步线程. 线程4(且这么叫)被调用做读文件操作. 线程4在释放后又被循环里的任务调用。
是否可以猜测因为改大了缓冲区,程序认为可以一次读入, I/O 请求很小, 异步操作同步完成? (但CompletedSynchronously 始终为false )
结论:这里头很强大 有很多优化,老老实实用吧 (韦恩卑鄙语)
参考链接
.Net在每个进程中设置一个ThreadPool, 此ThreadPool中有两种类型的线程:CLR worker threads和completionPortThreads;或者说.Net在一个进程中维护着2个线程池,一个同步线程池(CLR worker threads pool),一个异步IO线程池(completionPortThreads pool). 从类库的方法看,也确实做了区分:
public static bool SetMaxThreads(int workerThreads, int completionPortThreads);
public static bool SetMinThreads(int workerThreads, int completionPortThreads);
但两者并不是桥归桥路归路互不影响的。
int wt;
int ct;
ThreadPool.SetMinThreads(3, 3);
ThreadPool.SetMaxThreads(3, 3);
ManualResetEvent mre = new ManualResetEvent(false);
Stopwatch watch = new Stopwatch();
watch.Start();
WebRequest request = HttpWebRequest.Create("http://www.google.com.hk/");
request.BeginGetResponse(ar =>
{
Thread.Sleep(5000);
ThreadPool.GetAvailableThreads(out wt, out ct);
Console.WriteLine("{0} :Response wt num:{1} ct num {2}", watch.Elapsed, wt, ct);
var response = request.EndGetResponse(ar);
Console.WriteLine(watch.Elapsed + ": Response Get");
}, null);
for (int i = 0; i < 20; i++)
{
ThreadPool.QueueUserWorkItem(index =>
{
Console.WriteLine(String.Format("{0}: {1} thread", watch.Elapsed, index));
mre.WaitOne();
}, i);
}
mre.WaitOne();
这段代码前面把池中最大CLR线程数和最大I/O线程数设置为3. 并推入超过CLR线程数量的工作任务造成阻塞,同时启用一个异步的调用。
结果显示WebRequest使用了一个IO线程,两者似乎互不影响。
![](http://hi.csdn.net/attachment/201112/1/0_1322728114V2RN.gif)
但把异步调用的代码放到循环后面,就会出现“ThreadPool 中没有足够的自由线程来完成该操作” 错误. 通过 查阅一些资料,了解到在 BeginGetResponse 的最后有一个IsThreadPoolLow 判断来查询池中有多少个可用工作线程。如果数量过少(少于 2 个),将会引发 InvalidOperationException。
通过把MaxThread分别设置为1或2,直接运行WebRequest异步调用可以证实。
ThreadPool.SetMinThreads(1, 3);
ThreadPool.SetMaxThreads(1, 3);
ManualResetEvent mre = new ManualResetEvent(false);
Stopwatch watch = new Stopwatch();
watch.Start();
WebRequest request = HttpWebRequest.Create("http://www.google.com.hk/");
request.BeginGetResponse(ar =>
{
var response = request.EndGetResponse(ar);
Console.WriteLine(watch.Elapsed + ": Response Get");
}, null);
结论:虽然确实有CLR线程和IO线程之分,但CLR线程池还是可能影响异步IO操作,要根据具体的实现。
[试验2] FileStream
既然 CLR线程池能影响异步IO,再通过一个实现来尝试猜测下具体的联系。
int wt;
int ct;
ThreadPool.SetMinThreads(5, 3);
ThreadPool.SetMaxThreads(5, 3);
ManualResetEvent mre = new ManualResetEvent(false);
Stopwatch watch = new Stopwatch();
watch.Start();
ThreadPool.GetAvailableThreads(out wt, out ct);
Console.WriteLine("{0} :Before read file. wt num:{1} ct num {2}", watch.Elapsed, wt, ct);
for (int i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(index =>
{
Console.WriteLine(string.Format("{0}:{1} thread started", watch.Elapsed, index));
mre.WaitOne();
}, i);
}
string path = @"D:\lab\path\test1.txt";
byte[] data = new byte[1024];
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, true);
stream.BeginRead(data, 0, 1024, ar =>
{
Thread.Sleep(5000);
int length = stream.EndRead(ar);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, length));
stream.Close();
ThreadPool.GetAvailableThreads(out wt, out ct);
Console.WriteLine("{0}: End read file. wt num:{1} ct num {2}", watch.Elapsed, wt, ct);
Console.WriteLine(string.Format("CompletedSynchronously:{0}", ar.CompletedSynchronously));
}, stream);
mre.WaitOne();
运行结果显示 FileStream的异步操作不会受CLR线程耗尽的影响,自己会调用一个IO线程。 同时, 与WebRequest实现不同, FileStream的异步操作实现不会做IsThreadPoolLow 判断,因此这里的For循环代码段与异步读文件代码段的顺序可以互换。
![](http://hi.csdn.net/attachment/201112/1/0_1322729979iI9m.gif)
当把缓冲区的大小设置的比byte[]大时,一个有趣的情况发生了
//...
byte[] data = new byte[20];
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 25, true);
stream.BeginRead(data, 0, 20, ar =>
//...
![](http://hi.csdn.net/attachment/201112/1/0_1322730719bEEJ.gif)
结果显示异步读操作使用了一个同步线程. 线程4(且这么叫)被调用做读文件操作. 线程4在释放后又被循环里的任务调用。
是否可以猜测因为改大了缓冲区,程序认为可以一次读入, I/O 请求很小, 异步操作同步完成? (但CompletedSynchronously 始终为false )
结论:这里头很强大 有很多优化,老老实实用吧 (韦恩卑鄙语)