多线程编程学习笔记——线程池(一)

接上文 多线程编程学习笔记——线程同步(一)

接上文 多线程编程学习笔记——线程同步(二)

接上文 多线程编程学习笔记——线程同步(三)

创建多线程操作是非常昂贵的,所以每个运行时间非常短的操作,创建多线程进行操作,可能并不能提高效率,反而降低了效率。

如果你有非常多的执行时间非常短的操作,那么适合作用线程池来提高效率,而不是自行创建多线程。

线程池,就是我们先分配一些资源到池子里,当我们需要使用时,则从池子中获取,用完了,再放回池子里。

.NET中的线程池是受CLR管理的,TheadTool类有一个QueueUserWorkItem静态方法,这个静态方法接受一个委托,代表用户自定义的一个异步操作,在这个方法被调用之后,委托会进入到内部队列中,如果池中没有线程,则创建一个工作线程,把第一个委托放入工作线程。如果继续放入委托,则池创建新的工作线程,直到工作线程数量达到上限。这时再放入委托,则不会创建新的工作线程,而是在队列中等待,直到有空闲的工作线程。

当线程池中所有操作都完成,而且没有新任务操作时,线程池会释放长时间不用的资源。

注意:放入线程池中的操作需要的时间要短,不要把需要长时间运行的操作放入线程池中,或阻塞工作线程。这将导致性能问题和非常难以调用的问题。

在ASP.NET中使用线程池要当心,ASP.NET中的线程池是一个共用线程池,如果线程池中的工作线程都用完了,则会造成WEB服务器对正常的HTTP请求无法提供服务。

一、     线程池中调用委托

1.代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; 

namespace ThreadPoolDemo
{

    public delegate string ThreadPoolRun(out int threadId);
    class Program
    {  

        static void Main(string[] args)
        {

            Console.WriteLine("开始测试线程池-委托。。。");
            int threadId = 0;
            ThreadPoolRun poolDele = RunThread;
            var t = new Thread(() => RunThread(out threadId));
            t.Start();
            t.Join();
            Console.WriteLine("线程ID {0} ",threadId);
            IAsyncResult r = poolDele.BeginInvoke(out threadId, Callback, "在线程池中同步调用回调函数");
            string result = poolDele.EndInvoke(out threadId, r);
            Console.WriteLine("线程池中工作线程ID :{0}", threadId);
            Console.WriteLine("返回结果:{0}",result); 

            Thread.Sleep(2000);
            Console.Read(); 

        }

        private static void  Callback(IAsyncResult r)
        {

            Console.WriteLine("开始调用回调函数。。。");
            Console.WriteLine("回调函数此时的状态 :{0}",r.AsyncState);
            Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread);
            Console.WriteLine("调用此回调函数的线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId);
        }

        private static string RunThread(out int threadId)
        {
            Console.WriteLine("开始工作。。。");       

            Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            threadId = Thread.CurrentThread.ManagedThreadId;
            return string.Format("此线程在线程池在的ID :{0}", threadId);
        }
    }
}

2.程序执行结果如下图。

上面的程序运行时,我们首先创建线程来执行委托操作,然后调用委托的BeginInvoke来执行回调方法,这个回调函数会在异步操作完成之后会被调用,并且会把一个自定义的值传给这个回调函数,最后我们会得到一个实现了IAsyncResult接口的result对象,当线程池的工作线程在进行工作时,允许我们继续其他操作。我们可以轮询result对象的IsCompleted属性,确定操作是否完成。也可以调用EndInvoke将IAsyncResult传给委托参数。

二、     线程池中放入异步操作

1.代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; 

namespace ThreadPoolDemo
{
    class Program
    {   

        static void Main(string[] args)
        {
            Console.WriteLine("开始测试线程池-QueueUserWorkItem。。。");
            const int x = 1;
            const int y = 2;
            string workState = "工作状态 2"; 

            ThreadPool.QueueUserWorkItem(AsyncOper);
            Thread.Sleep(1000);
            ThreadPool.QueueUserWorkItem(AsyncOper,"同步状态");
            Thread.Sleep(1000);

            ThreadPool.QueueUserWorkItem(status => {
                Console.WriteLine("操作状态 {0} ", status);
                Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            },"工作状态");

            ThreadPool.QueueUserWorkItem(_ => {
                Console.WriteLine("操作结果x+y= {0} ,{1}", x+y,workState);
                Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromSeconds(2));
            }, "工作状态"); 

            Thread.Sleep(2000);
            Console.Read();
        }

        private static void  AsyncOper(object status)
        {
            Console.WriteLine("操作状态 :{0} ",status??"null");

            Console.WriteLine("工作线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(2000);
        }  

    }
}

2.执行结果如下。程序执行了两次。

程序首先定义了一个AsyncOper方法,然后使用QueueUserWorkItem将这个方法放入线程池中,然后再次放入一个AsyncOper方法,不过这次给方法调用传一个对象。

代码中的调用Thread.sleep方法,是为了让线程池中的工作线程为新操作重用。请注意打印出来的ThradId,如果ThreadID一样则证明两个操作重用了同一个工作线程。

时间: 2024-10-13 12:15:21

多线程编程学习笔记——线程池(一)的相关文章

多线程编程学习笔记——线程同步(三)

接上文 多线程编程学习笔记——线程同步(一) 接上文 多线程编程学习笔记——线程同步(二) 七.使用Barrier类 Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了SignalAndWait方法后该回调函数就会被执行. 1.代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //

多线程编程学习五(线程池的创建)

一.概述 New Thread的弊端如下:       a.每次New Thread新建对象性能差.       b.线程缺乏统一的管理,可能无限制的新建线程,相互之间竞争,极可能占用过多的系统资源导致死机 或者 OOM.       c.缺乏更多功能,如定时执行.定期执行.线程中断. Java提供的四种线程池的好处在于:       a.重用存在的线程,减少对象创建.消亡的开销,性能佳.       b.可有效控制最大并发线程数.提供系统资源的使用率,同时避免过多资源竞争,避免堵塞.     

多线程编程学习笔记——async和await(二)

接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步调用 . 1.示例代码如下. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Thread

多线程编程学习笔记——async和await(三)

接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多个并行的异步操作使用await时聚合异常. 1.程序示例代码如下. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;

多线程编程学习笔记——使用并发集合(三)

接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 四.   使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费任务的工作者间如何扩展工作量. 1.程序代码如下. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Sy

多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Ta

Java多线程编程(学习笔记)

一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过多线程的使用,可以编写出非常高效的程序.但如果创建了太多的线程,程序执行的效率反而会降低. 同时上下文的切换开销也很重要,如果创建太多的线程,CPU花费在上下文的切换时间将对于执行程序的时间. 二.Java多线程编程 概念 在学习多线程时,我们应该首先明白另外一个概念. 进程:是计算机中的程序关于某

VC多线程编程学习笔记(一)

最近两天在学多线程编程,有了一些心得,写下来和大家一起共勉.文中一些部分引用了韩耀旭的文章<多线程编程>http://www.vckbase.com/document/viewdoc/?id=1704和MSDN资料. 一.缘起 工作上要用到串口编程,本来一直是用mscomm控件来进行串口通讯的,后来觉得这个控件功能不灵活,想直接使用api编程,那就不可避免的要使用多线程技术:用一个支线程一直挂在那里监听串口,就不影响主线程的消息循环了. 二.为何要用多线程 有时候需要把程序的运行挂起一段时间,

多线程编程学习笔记

多线程编程 目录 线程概述 线程的创建 创建线程程序 线程同步 守护线程 线程之间的相互通讯 线程池和java.util.concurrent包 一.概述 1.相关概念 进程(Process):程序(任务)执行的过程,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程,共享内存,共享文件.比如在Windows系统中,一个运行的exe就是一个进程. 线程(Thread):进程中的一个执行流程,一个进程中可以运行多个线程.线程总是属于某个进程,进程中的多个线程共享进程的内存.现在的操作系