前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CLR线程池边缘情况测试

CLR线程池边缘情况测试

作者头像
小蜜蜂
修改2019-07-16 17:18:05
5680
修改2019-07-16 17:18:05
举报
文章被收录于专栏:明丰随笔明丰随笔

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

线程池的作用和CLR线程池

IOCP异步优化

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

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

测试场景1:

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

测试结果:

结论:

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

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

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

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

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

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

测试1代码:

代码语言:javascript
复制
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. 任务只是借用一个线程来做事,完成以后便会还回。

测试代码:

代码语言:javascript
复制
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; }
} 
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 明丰随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档