出售域名 11365.com.cn
有需要请联系 16826375@qq.com
在手机上浏览
在手机上浏览

多线程之线程池

发布日期:2022-09-09

延申阅读:

1) 多线程之Thread

2) 多线程之线程池

3) 多线程之Task

 

一、线程池的概念
线程Thread创建和维护,需要消耗很多系统资源,频繁的创建销毁,使得系统性能下降。因此微软提出了线程池的概念。
我们可以把线程池想像成一个容器,里面装了很多线程,需要的时候从里面取出使用,使用完了扔在里面备用。
线程池(ThreadPool)是一个静态类,可以直接使用。
ThreadPool.GetMinThreads(工作线程数,I/O线程数) 读默认最小线程数
ThreadPool.GetMaxThreads(工作线程数,I/O线程数) 读默认最大线程数

ThreadPool.SetMinThreads(工作线程数,I/O线程数) 设置最小线程数
ThreadPool.SetMaxThreads(工作线程数,I/O线程数) 设置最大线程数

一般默认的最小线程数就是CPU的内核数,比如我的CPU是12核,那么最小线程数是12。
设置最小/最大线程数都不要小于CPU核心数,不然会造成性能问题。
设置最大线程数尽量数量大一些,以防止线程不够用时,进入等待或者死锁状态。

线程池中的线程默认都是后台线程!

线程池适用于运行短而快的任务!

 

二、线程池的使用
把需要执行的任务放到工作队列中,系统会在适当的时候调用它。
ThreadPool.QueueUserWorkItem

下面例子介绍了线程池的简单使用。

private static AutoResetEvent autoReset = new AutoResetEvent(false);
static void Main(string[] args)
{
    //执行委托任务
    ThreadPool.QueueUserWorkItem(p =>
    {
        Console.WriteLine("李白(1)字:"   p);
    },"太白");

    //执行方法任务
    ThreadPool.QueueUserWorkItem(ThreadPoolMethod, "太白");

    autoReset.WaitOne();//等待线程完成
    Console.WriteLine("执行完成!");
}

static void ThreadPoolMethod(object p) //注意参数类型必须是 object
{
    Console.WriteLine("李白(2)字:"   p);
    autoReset.Set();
}

 

三、异步编程

通过调用线程池的线程,运行委托,可以实现异步方法。
在这之前,我也一直有个困惑,那就是线程不就是并发的吗?不就是异步的吗?那为什么还要使用委托实现异步效果呢?
答案就是线程只是一个运行的过程,本身并不会有返回值,当我们执行一个线程,想要得到这个执行结果时,就要用到异步委托了。

//定义一个要执行的方法

static string ThreadPoolAsyncMethod()
{            
    return "线程池示例";
}

1、同步委托

static void Main(string[] args)
{
    Func<string> tpad = ThreadPoolAsyncMethod; //委托方法
    var result = tpad.BeginInvoke(null, null);
    result.AsyncWaitHandle.WaitOne(); //等待异步完成
    var retValue = tpad.EndInvoke(result); //读取值

    Console.WriteLine("操作前");
    Console.WriteLine("异步值:" retValue);
    Console.WriteLine("操作后");
}

可以看到这里并没有实现异步,主线程一直阻塞,直到tpad委托执行完成。这当然不是我们想要的效果。

2、异步委托

static void Callback(IAsyncResult r)
{
    var target=(Func<string>)r.AsyncState;
    var result = target.EndInvoke(r);
    Console.WriteLine("异步结果:"  result);
}

static void Main(string[] args)
{
    Func<string> tpad = ThreadPoolAsyncMethod; //委托方法
    var result = tpad.BeginInvoke(Callback, tpad); //实现异步的主要操作,就是回调
    //result.AsyncWaitHandle.WaitOne(); //等待异步完成
    //var retValue = tpad.EndInvoke(result); //读取值

    Console.WriteLine("操作前");
    //Console.WriteLine("异步值:" retValue);
    Console.WriteLine("操作后");
}

可以看到,异步并没有阻塞主线程,同时异步委托并行执行。

注:调用BeginInvoke会自动调用一个线程池中的线程,如果线程池中没有线程,系统自动创建。