关于线程池同步异步的两个试验

1 篇文章 0 订阅
1 篇文章 0 订阅
[试验一]  WebRequest
参考链接
.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线程,两者似乎互不影响。




但把异步调用的代码放到循环后面,就会出现“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循环代码段与异步读文件代码段的顺序可以互换。


当把缓冲区的大小设置的比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 =>

//...


结果显示异步读操作使用了一个同步线程. 线程4(且这么叫)被调用做读文件操作. 线程4在释放后又被循环里的任务调用。
是否可以猜测因为改大了缓冲区,程序认为可以一次读入, I/O 请求很小异步操作同步完成? (但CompletedSynchronously 始终为false )

结论:这里头很强大 有很多优化,老老实实用吧 (韦恩卑鄙语)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值