专栏首页明丰随笔CLR线程池边缘情况测试

CLR线程池边缘情况测试

对于CLR的线程池的概念请看:

线程池的作用和CLR线程池

IOCP异步优化

本篇内容主要讨论CLR线程池的边缘情况。

一、对工作者线程进行测试。

测试场景1:

设置工作者线程的下限数量5,上限数量10,给线程池一瞬间安排20个任务,每个任务占用线程时间18秒,然后观察线程池在对待线程数量的上下限的反应,以及完成一个任务之后返回线程池中的线程之后的情况。

测试结果:

结论:

1. 运行的工作者线程数量在下限以下,会尽可能多立即执行任务。(前5行)

2. 线程数量每秒不超过2个的频率创建线程。(6-10行)

3. 运行的工作者线程数量到达上限,会停止创建新线程。(10行)

4. 在旧任务执行完毕后,新任务立即执行。(11-20行)

5. 线程并不“属于”任何一个任务,或者说任务并不“拥有”线程。

6. 任务只是借用一个线程来做事,完成以后便会还回。

测试1代码:

ThreadPool.SetMinThreads(5, 5);
ThreadPool.SetMaxThreads(10, 10);
Console.WriteLine("--Only worker threads testing start--");
Stopwatch watch = new Stopwatch();
watch.Start();
WaitCallback callback = index =>
{    
    Console.WriteLine(String.Format("Task {0}  started;Seconds {1}", index, watch.Elapsed.TotalSeconds));    
    double sleepDuring = 18000 - Math.Floor(watch.Elapsed.TotalSeconds) * 1000;    
    Thread.Sleep((int)sleepDuring);
};
for (int i = 1; i <= 20; i++) {    
    ThreadPool.QueueUserWorkItem(callback, i);
}
Console.ReadKey();
Console.WriteLine("--Only worker threads testing end--");
Console.ReadKey();

二、对异步IO请求进行测试。

测试场景2:

设置工作者线程的下限数量5,上限数量10。

IO完成线程的下限数量5,上限数量10。

给线程池一瞬间安排15个异步IO任务,每个任务占用线程时间10秒,然后发送异步IO请求,之后观察线程池在对待线程数量的上下限的反应。

测试结果:

结论:

1. 运行的工作者线程数量在下限以下,会尽可能多立即执行任务。(前5行)

2. 线程数量每秒不超过2个的频率创建线程。(6-10行)

3. 运行的工作者线程数量到达上限,会停止创建新线程。(10行)

4. 工作者线程数量到达上限,任何一个工作者线程进行异步IO请求就会报Exception。

5. 工作线程和IO完成线程在线程池里面完全独立,互不影响。

测试场景3:

设置工作者线程的下限数量5,上限数量20。

IO完成线程的下限数量5,上限数量10。

给线程池一瞬间安排15个异步IO任务,每个任务占用线程时间10秒,然后发送异步IO请求,之后观察线程池在对待线程数量的上下限的反应。

测试数据:

当线程池有足够的工作者线程时,可以正常调用异步IO请求。当我们使用IO异步优化服务器的时候,必须要保证CLR线程池的工作者线程不能被100%占用,要保证有多余的工作者线程,这样才能正常工作。

测试场景4:

设置工作者线程的下限数量5,上限数量30,IO完成线程的下限数量5,上限数量10,给线程池一瞬间安排20个异步IO任务,然后异步IO请求回调中占用IO线程10秒。观察线程池中IO线程的上下限反应。

测试结果:

结论:

1. 运行的IO线程数量在下限以下,会尽可能多立即执行IO回调任务。(21-25行)

2. IO线程数量每秒不超过2个的频率创建线程。(26-30行)

3. 运行的IO线程数量到达上限,会停止创建新线程。(30行)

4. 在旧任务执行完毕后,新任务立即执行。(31-40行)

5. 线程并不“属于”任何一个任务,或者说任务并不“拥有”线程。

6. 任务只是借用一个线程来做事,完成以后便会还回。

测试代码:

class Program
{    
    static void Main(string[] args) 
    {
        ThreadPool.SetMinThreads(30, 5);        
        ThreadPool.SetMaxThreads(30, 10);
        Console.WriteLine("--Worker threads and completion port threads testing start--");        
        Stopwatch watch = new Stopwatch();        
        watch.Start();
        WaitCallback callback = index => {            
            Console.WriteLine(String.Format("Task {0}  started; Seconds {1}", index, watch.Elapsed.TotalSeconds));            
            IOCP_Handle(index, watch);        
        };        
        for (int i = 1; i <= 20; i++) {            
            ThreadPool.QueueUserWorkItem(callback, i);        
        }        
        Console.ReadKey();        
        Console.WriteLine("--Worker threads and completion port threads testing end--");        
        Console.ReadKey();  
    }
    
    private static void IOCP_Handle(object index, Stopwatch watch) 
    {        
        WebRequest request = HttpWebRequest.Create(string.Format("https://www.ef.com/Common/css/fonts.css?v={0}", index.ToString()));
        CallBackParam cb = new CallBackParam()        
        {            
            Index = (int)index,            
            Request = request,            
            Watch = watch        
        };        
        try        
        {            
            request.BeginGetResponse(HandleAsyncCallback, cb);        
        } 
        catch (Exception ex) 
        {            
            Console.WriteLine(string.Format("Task {0} BeginGetResponse; Seconds {1} \r\n {2}", index.ToString(), watch.Elapsed.TotalSeconds, ex.Message));        
        }    
    }
    
    static void HandleAsyncCallback(IAsyncResult ar) 
    {        
        CallBackParam cb = (CallBackParam)ar.AsyncState;        
        string index = cb.Index.ToString();        
        Console.WriteLine(String.Format("Task {0} finished; Seconds {1}", index, cb.Watch.Elapsed.TotalSeconds));        
        try 
        {            
            WebResponse response = cb.Request.EndGetResponse(ar);            
            response.Close();        
        }        
        catch (Exception ex)        
        {            
            Console.WriteLine(string.Format("Task {0} EndGetResponse. \r\n {1}", index.ToString(), ex.Message));        
        }        
        finally        
        {            
            cb.Request.Abort();        
        }        
        double sleepDuring = 10000 - Math.Floor(cb.Watch.Elapsed.TotalSeconds) * 1000;        
        Thread.Sleep((int)sleepDuring);    
    }
}

public class CallBackParam
{    
    public WebRequest Request { get; set; }    
    public int Index { get; set; }    
    public Stopwatch Watch { get; set; }
} 

本文分享自微信公众号 - 明丰随笔(liumingfengwx2),作者:刘明丰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 线程池的作用和CLR线程池

    在程序的世界里,如果创建某种对象所需要的代价太高,同时这个对象又可以反复使用,那么我们往往就会准备一个容器,用来保存一批这样的对象。当我们要用这种对象时,就不需...

    小蜜蜂
  • IOCP异步优化

    2. IO操作: CPU会把内存中的程序委托给其他的网络、磁盘等驱动程序,让这些外部的驱动程序来进行具体的处理,处理完成以后再返回给内存程序。对于这两类操作的优...

    小蜜蜂
  • 浅谈.Net反射 11

    浅谈.Net反射系列基本来到了尾声,本文主要从.Net Framework的源码角度去分析:

    小蜜蜂
  • 多线程设计模式解读3—Two-phase Termination(两阶段终止)模式

    有时候,我们希望提前结束线程,但安全可靠地停止线程,并不是一件容易的事情,如果立即停止线程,会使共享的数据结构处于不一致的状态,如目前已经废弃使用的Thread...

    java达人
  • 单例模式的六种花式写法

    单例模式是一种常用的设计模式,其定义是单例对象类只允许一个实例存在,实现的核心原理是构造函数私有化。使用单例可以节省内存开销,也是现实场景中的一种映射,比如一台...

    蜻蜓队长
  • 并发编程-加锁机制

    本文翻译自《Java Concurrency ?In ?Practice》,定期放送 ,让你利用碎片时间悄悄的看了一本书! 我们的文章是系列的。所以先请允许...

    ImportSource
  • 面试官由浅入深的面试套路

    应聘者:1、Runnable接口可以避免单继承的限制,要是继承Thread类的话,那么就不能继承其他的类了,因为只能单继承,如果实现了接口Runnale后,还可...

    java乐园
  • 你必须要知道的锁原理、锁优化、CAS、AQS

    出处:https://www.jianshu.com/p/e674ee68fd3f

    好好学java
  • Java中的锁原理、锁优化、CAS、AQS

    结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

    Java团长
  • 高并发编程-ReentrantLock公平锁深入解析

    ReentrantLock是一个可重入的互斥锁,它不但具有synchronized实现的同步方法和同步代码块的基本行为和语义,而且具备很强的扩展性。Reentr...

    JavaQ

扫码关注云+社区

领取腾讯云代金券