最新更新 sitemap 网站制作设计本站搜索
网页设计
国外网站 韩国网站 个人主页 手提袋设计 CSS 网页特效 平面设计 网站设计 Flash CMS技巧 服装网站 php教程 photoshop 画册 服务器选用 数据库 Office
虚拟主机 域名注册 云主机 网页设计 客服QQ:8208442
当前位置:首页 > 编程开发 > asp教程

浅谈.NET下的多线程和并行计算

日期:02-16    来源:中国设计秀    作者:cnwebshow.com

这节我们按照线程池的核心思想来自定义一个简单的线程池:ti0中国设计秀
ti0中国设计秀
1) 池中使用的线程不少于一定数量,不多于一定数量ti0中国设计秀
ti0中国设计秀
2) 池中线程不够的时候创建,富裕的时候收回ti0中国设计秀
ti0中国设计秀
3) 任务排队,没有可用线程时,任务等待ti0中国设计秀
ti0中国设计秀
我们的目的只是实现这些“需求”,不去考虑性能(比如等待一段时间再去创建新的线程等策略)以及特殊的处理(异常),在实现这个需求的过程中我们也回顾了线程以及线程同步的基本概念。ti0中国设计秀
ti0中国设计秀
首先,把任务委托和任务需要的状态数据封装一个对象:ti0中国设计秀
ti0中国设计秀
public class WorkItemti0中国设计秀
{ti0中国设计秀
    public WaitCallback Action { get; set; }ti0中国设计秀
    public object State { get; set; }ti0中国设计秀
ti0中国设计秀
    public WorkItem(WaitCallback action, object state)ti0中国设计秀
    {ti0中国设计秀
        this.Action = action;ti0中国设计秀
        this.State = state;ti0中国设计秀
    }ti0中国设计秀
}然后来创建一个对象作为线程池中的一个线程:ti0中国设计秀
ti0中国设计秀
public class SimpleThreadPoolThreadti0中国设计秀
{ti0中国设计秀
    PRivate object locker = new object();ti0中国设计秀
    private AutoResetEvent are = new AutoResetEvent(false);ti0中国设计秀
    private WorkItem wi;ti0中国设计秀
    private Thread t;ti0中国设计秀
    private bool b = true;ti0中国设计秀
    private bool isWorking;ti0中国设计秀
ti0中国设计秀
    public bool IsWorkingti0中国设计秀
    {ti0中国设计秀
        getti0中国设计秀
        {ti0中国设计秀
            lock (locker)ti0中国设计秀
            {ti0中国设计秀
                return isWorking;ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
    public event Action<SimpleThreadPoolThread> WorkComplete;ti0中国设计秀
ti0中国设计秀
    public SimpleThreadPoolThread()ti0中国设计秀
    {ti0中国设计秀
        lock (locker)ti0中国设计秀
        {ti0中国设计秀
            // 当前没有实际任务ti0中国设计秀
            isWorking = false;ti0中国设计秀
        }ti0中国设计秀
        t = new Thread(Work) { IsBackground = true };ti0中国设计秀
        t.Start();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public void SetWork(WorkItem wi)ti0中国设计秀
    {ti0中国设计秀
        this.wi = wi;ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public void StartWork()ti0中国设计秀
    {ti0中国设计秀
        // 发出信号ti0中国设计秀
        are.Set();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public void StopWork()ti0中国设计秀
    {ti0中国设计秀
        // 空任务ti0中国设计秀
        wi = null;ti0中国设计秀
        // 停止线程循环ti0中国设计秀
        b = false;ti0中国设计秀
        // 发出信号结束线程ti0中国设计秀
        are.Set();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    private void Work()ti0中国设计秀
    {ti0中国设计秀
        while (b)ti0中国设计秀
        {ti0中国设计秀
            // 没任务,等待信号ti0中国设计秀
            are.WaitOne();ti0中国设计秀
            if (wi != null)ti0中国设计秀
            {ti0中国设计秀
                lock (locker)ti0中国设计秀
                {ti0中国设计秀
                    // 开始ti0中国设计秀
                    isWorking = true;ti0中国设计秀
                }ti0中国设计秀
                // 执行任务ti0中国设计秀
                wi.Action(wi.State);ti0中国设计秀
                lock (locker)ti0中国设计秀
                {ti0中国设计秀
                    // 结束ti0中国设计秀
                    isWorking = false;ti0中国设计秀
                }ti0中国设计秀
                // 结束事件ti0中国设计秀
                WorkComplete(this);ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }代码的细节可以看注释,对这段代码的整体结构作一个说明:ti0中国设计秀
ti0中国设计秀
1) 由于这个线程是被线程池中任务复用的,所以线程的任务处于循环中,除非线程池打算回收这个线程,否则不会退出循环结束任务ti0中国设计秀
ti0中国设计秀
2) 使用自动信号量让线程没任务的时候等待,由线程池在外部设置任务后发出信号来执行实际的任务,执行完毕后继续等待ti0中国设计秀
ti0中国设计秀
3) 线程公开一个完成的事件,线程池可以挂接处理方法,在任务完成后更新线程池状态ti0中国设计秀
ti0中国设计秀
4) 线程池中的所有线程都是后台线程ti0中国设计秀
ti0中国设计秀
下面再来实现线程池:ti0中国设计秀
ti0中国设计秀
public class SimpleThreadPool : IDisposableti0中国设计秀
{ti0中国设计秀
    private object locker = new object();ti0中国设计秀
    private bool b = true;ti0中国设计秀
    private int minThreads;ti0中国设计秀
    private int maxThreads;ti0中国设计秀
    private int currentActiveThreadCount;ti0中国设计秀
    private List<SimpleThreadPoolThread> simpleThreadPoolThreadList = new List<SimpleThreadPoolThread>();ti0中国设计秀
    private Queue<WorkItem> workItemQueue = new Queue<WorkItem>();ti0中国设计秀
ti0中国设计秀
    public int CurrentActiveThreadCountti0中国设计秀
    {ti0中国设计秀
        getti0中国设计秀
        {ti0中国设计秀
            lock (locker)ti0中国设计秀
            {ti0中国设计秀
                return currentActiveThreadCount;ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public int CurrentThreadCountti0中国设计秀
    {ti0中国设计秀
        getti0中国设计秀
        {ti0中国设计秀
            lock (locker)ti0中国设计秀
            {ti0中国设计秀
                return simpleThreadPoolThreadList.Count;ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public int CurrentQueuedWorkCountti0中国设计秀
    {ti0中国设计秀
        getti0中国设计秀
        {ti0中国设计秀
            lock (locker)ti0中国设计秀
            {ti0中国设计秀
                return workItemQueue.Count;ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public SimpleThreadPool()ti0中国设计秀
    {ti0中国设计秀
        minThreads = 4;ti0中国设计秀
        maxThreads = 25;ti0中国设计秀
        Init();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public SimpleThreadPool(int minThreads, int maxThreads)ti0中国设计秀
    {ti0中国设计秀
        if (minThreads > maxThreads)ti0中国设计秀
            throw new ArgumentException("minThreads > maxThreads", "minThreads,maxThreads");ti0中国设计秀
        this.minThreads = minThreads;ti0中国设计秀
        this.maxThreads = maxThreads;ti0中国设计秀
        Init();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public void QueueUserWorkItem(WorkItem wi)ti0中国设计秀
    {ti0中国设计秀
        lock (locker)ti0中国设计秀
        {ti0中国设计秀
            // 任务入列ti0中国设计秀
            workItemQueue.Enqueue(wi);ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    private void Init()ti0中国设计秀
    {ti0中国设计秀
        lock (locker)ti0中国设计秀
        {ti0中国设计秀
            // 一开始创建最小线程ti0中国设计秀
            for (int i = 0; i < minThreads; i++)ti0中国设计秀
            {ti0中国设计秀
                CreateThread();ti0中国设计秀
            }ti0中国设计秀
            currentActiveThreadCount = 0;ti0中国设计秀
        }ti0中国设计秀
        new Thread(Work) { IsBackground = true }.Start();ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    private SimpleThreadPoolThread CreateThread()ti0中国设计秀
    {ti0中国设计秀
        SimpleThreadPoolThread t = new SimpleThreadPoolThread();ti0中国设计秀
        // 挂接任务结束事件ti0中国设计秀
        t.WorkComplete += new Action<SimpleThreadPoolThread>(t_WorkComplete);ti0中国设计秀
        // 线程入列ti0中国设计秀
        simpleThreadPoolThreadList.Add(t);ti0中国设计秀
        return t;ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    private void Work()ti0中国设计秀
    {ti0中国设计秀
        // 线程池主循环ti0中国设计秀
        while (b)ti0中国设计秀
        {ti0中国设计秀
            Thread.Sleep(100);ti0中国设计秀
            lock (locker)ti0中国设计秀
            {ti0中国设计秀
                // 如果队列中有任务并且当前线程小于最大线程ti0中国设计秀
                if (workItemQueue.Count > 0 && CurrentActiveThreadCount < maxThreads)ti0中国设计秀
                {ti0中国设计秀
                    WorkItem wi = workItemQueue.Dequeue();ti0中国设计秀
                    // 寻找闲置线程ti0中国设计秀
                    SimpleThreadPoolThread availableThread = simpleThreadPoolThreadList.FirstOrDefault(t => t.IsWorking == false);ti0中国设计秀
                    // 无则创建ti0中国设计秀
                    if (availableThread == null)ti0中国设计秀
                        availableThread = CreateThread();ti0中国设计秀
                    // 设置任务ti0中国设计秀
                    availableThread.SetWork(wi);ti0中国设计秀
                    // 开始任务ti0中国设计秀
                    availableThread.StartWork();ti0中国设计秀
                    // 增加个活动线程ti0中国设计秀
                    currentActiveThreadCount++;ti0中国设计秀
                }ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    private void t_WorkComplete(SimpleThreadPoolThread t)ti0中国设计秀
    {ti0中国设计秀
        lock (locker)ti0中国设计秀
        {ti0中国设计秀
            // 减少个活动线程ti0中国设计秀
            currentActiveThreadCount--;ti0中国设计秀
            // 如果当前线程数有所富裕并且比最小线程多ti0中国设计秀
            if ((workItemQueue.Count + currentActiveThreadCount) < minThreads && CurrentThreadCount > minThreads)ti0中国设计秀
            {ti0中国设计秀
                // 停止已完成的线程ti0中国设计秀
                t.StopWork();ti0中国设计秀
                // 从线程池删除线程ti0中国设计秀
                simpleThreadPoolThreadList.Remove(t);ti0中国设计秀
            }ti0中国设计秀
        }ti0中国设计秀
    }ti0中国设计秀
ti0中国设计秀
    public void Dispose()ti0中国设计秀
    {ti0中国设计秀
        // 所有线程停止ti0中国设计秀
        foreach (var t in simpleThreadPoolThreadList)ti0中国设计秀
        {ti0中国设计秀
            t.StopWork();ti0中国设计秀
        }ti0中国设计秀
        // 线程池主循环停止ti0中国设计秀
        b = false;ti0中国设计秀
    }ti0中国设计秀
}线程池的结构如下: ti0中国设计秀
ti0中国设计秀
1) 在构造方法中可以设置线程池最小和最大线程ti0中国设计秀
ti0中国设计秀
2) 维护一个任务队列和一个线程池中线程的列表 ti0中国设计秀
ti0中国设计秀
3) 初始化线程池的时候就创建最小线程数量定义的线程 ti0中国设计秀
ti0中国设计秀
4) 线程池主循环每20毫秒就去处理一次,如果有任务并且线程池还可以处理任务的话,先是找闲置线程,找不到则创建一个 ti0中国设计秀
ti0中国设计秀
5) 通过设置任务委托以及发出信号量来开始任务 ti0中国设计秀
ti0中国设计秀
6) 线程池提供了三个属性来查看当前活动线程数,当前总线程数和当前队列中的任务数 ti0中国设计秀
ti0中国设计秀
7) 任务完成的回调事件中我们判断如果当前线程有富裕并且比最小线程多则回收线程 ti0中国设计秀
ti0中国设计秀
8) 线程池是IDispose对象,在Dispose()方法中停止所有线程后停止线程池主循环ti0中国设计秀
ti0中国设计秀
写一段代码来测试线程池: ti0中国设计秀
ti0中国设计秀
using (SimpleThreadPool t = new SimpleThreadPool(2, 4))ti0中国设计秀
{ti0中国设计秀
    Stopwatch sw2 = Stopwatch.StartNew();ti0中国设计秀
    for (int i = 0; i < 10; i++)ti0中国设计秀
    {ti0中国设计秀
        t.QueueUserWorkItem(new WorkItem((index =>ti0中国设计秀
        {ti0中国设计秀
            Console.WriteLine(string.Format("#{0} : {1} / {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("mm:ss"), index));ti0中国设计秀
            Console.WriteLine(string.Format("CurrentActiveThread: {0} / CurrentThread: {1} / CurrentQueuedWork: {2}", t.CurrentActiveThreadCount, t.CurrentThreadCount, t.CurrentQueuedWorkCount));ti0中国设计秀
            Thread.Sleep(1000);ti0中国设计秀
        }), i));ti0中国设计秀
    }ti0中国设计秀
    while (t.CurrentQueuedWorkCount > 0 || t.CurrentActiveThreadCount > 0)ti0中国设计秀
    {ti0中国设计秀
        Thread.Sleep(10);ti0中国设计秀
    }ti0中国设计秀
    Console.WriteLine("All work completed");ti0中国设计秀
    Console.WriteLine(string.Format("CurrentActiveThread: {0} / CurrentThread: {1} / CurrentQueuedWork: {2}", t.CurrentActiveThreadCount, t.CurrentThreadCount, t.CurrentQueuedWorkCount));ti0中国设计秀
    Console.WriteLine(sw2.ElapsedMilliseconds);ti0中国设计秀
} 代码中我们向线程池推入10个任务,每个任务需要1秒执行,任务执行前输出当前任务的所属线程的Id,当前时间以及状态值。然后再输出线程池的几个状态属性。主线程循环等待所有任务完成后再次输出线程池状态属性以及所有任务完成耗费的时间:ti0中国设计秀

本文引用地址:/bc/article_46162.html
网站地图 | 关于我们 | 联系我们 | 网站建设 | 广告服务 | 版权声明 | 免责声明