最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#實(shí)現(xiàn)自定義線程池實(shí)例代碼

 更新時(shí)間:2022年07月18日 16:36:30   作者:奮斗的大橙子  
這篇文章介紹了C#實(shí)現(xiàn)自定義線程池的實(shí)例代碼,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在項(xiàng)目中如果是web請(qǐng)求時(shí)候,IIS會(huì)自動(dòng)分配一個(gè)線程來進(jìn)行處理,如果很多個(gè)應(yīng)用程序共享公用一個(gè)IIS的時(shí)候,線程分配可能會(huì)出現(xiàn)一個(gè)問題(當(dāng)然也是我的需求造成的)

之前在做項(xiàng)目的時(shí)候,有一個(gè)需求,就是當(dāng)程序啟動(dòng)的時(shí)候,希望能夠啟動(dòng)一定數(shù)目的線程,然后每一個(gè)線程始終都是在運(yùn)行的狀態(tài),不進(jìn)行釋放,然后循環(huán)去做一些事情。那么IIS的線程管理可能就不是我想要的,因?yàn)槲蚁胛业囊恍┏绦?,只用我開啟的線程來做工作。也就是說我想模擬一個(gè)線程池,每次有一個(gè)調(diào)用的時(shí)候從自定義線程池中取出一個(gè),用完再放回去。

談?wù)勎业乃悸罚?/p>

1.程序一啟動(dòng)就通過for循環(huán)來創(chuàng)建,一定數(shù)目的線程(這個(gè)數(shù)目是可以配置的)

2.至少要有三個(gè)容器來存儲(chǔ)線程,分別是工作線程隊(duì)列和空閑線程隊(duì)列以及等待隊(duì)列

3.使用線程中的AutoResetEvent類,初始每一個(gè)線程都是unsignaled狀態(tài),線程一啟動(dòng)就一直在循環(huán)調(diào)用WaitOne()方法,那么每次外部調(diào)用的時(shí)候,都調(diào)用一次這個(gè)類實(shí)例對(duì)象的set,線程然后就可以繼續(xù)做下面的工作了。

4.至少兩個(gè)方法:

第一個(gè)開放給外部,讓外部的方法能夠被傳入執(zhí)行,然后這個(gè)方法能夠判斷空閑隊(duì)列,等待隊(duì)列,以及工作隊(duì)列的狀態(tài),如果傳入的時(shí)候發(fā)現(xiàn),空閑隊(duì)列有空閑的線程就直接,將任務(wù)委托給空閑隊(duì)列的一個(gè)線程執(zhí)行,否則把它放到等待隊(duì)列。

第二個(gè)方法,需要能夠?qū)⒐ぷ魍瓿傻木€程從工作隊(duì)列移動(dòng)到空閑隊(duì)列,然后判斷一下等待隊(duì)列是不是有任務(wù),有的話就交給空閑隊(duì)列里面的線程來執(zhí)行。

體思路如上,可以試試先寫一下。

1.因?yàn)槊總€(gè)線程都有一個(gè)AutoResetEvent的實(shí)例,所以最好把Thread進(jìn)行封裝,變成我們自己的Thread。

    public class Task
    {
        #region Variable
        //一個(gè)AutoResetEvent實(shí)例
        private AutoResetEvent _locks = new AutoResetEvent(false);
        //一個(gè)Thread實(shí)例
        private Thread _thread;
        // 綁定回調(diào)方法,就是外部實(shí)際執(zhí)行的任務(wù)
        public Action _taskAction;

        //定義一個(gè)事件用來綁定工作完成后的操作,也就是4中所說的工作隊(duì)列向空閑隊(duì)列移動(dòng)
        public event Action<Task> WorkComplete;

        /// <summary>
        ///設(shè)置線程擁有的Key
        /// </summary>
        public string Key { get; set; }

        #endregion

        //線程需要做的工作
        private void Work()
        {
            while (true)
            {
                //判斷信號(hào)狀態(tài),如果有set那么 _locks.WaitOne()后的程序就繼續(xù)執(zhí)行
                _locks.WaitOne();
                _taskAction();
                //執(zhí)行事件
                WorkComplete(this);
            }
        }

        #region event
        //構(gòu)造函數(shù)
        public Task()
        {
            //スレッドオブジェクトを初期化する
            _thread = new Thread(Work);
            _thread.IsBackground = true;
            Key = Guid.NewGuid().ToString();
            //線程開始執(zhí)行
            _thread.Start();
        }

        //Set開起信號(hào)
        public void Active()
        {
            _locks.Set();
        }

        #endregion
    }

解釋:上面那個(gè)Key的作用,因?yàn)槎鄠€(gè)線程同時(shí)進(jìn)行的時(shí)候,我們并不知道哪一個(gè)線程的工作先執(zhí)行完,所以說上面的工作隊(duì)列,實(shí)際上應(yīng)該用一個(gè)字典來保存,這樣我們就能在一個(gè)線程結(jié)束工作之后,通過這 里的KEY(每個(gè)線程不一樣),來進(jìn)行定位了。

2.線程封裝好了,然后就可以實(shí)現(xiàn)線程池了

    public class TaskPool
    {
        #region Variable
        //創(chuàng)建的線程數(shù)
        private int _threadCount;
        //空閑線程隊(duì)列
        private Queue<Task> _freeQueue;
        //工作線程字典(為什么?)
        private Dictionary<string, Task> _workingDictionary;
        //空閑隊(duì)列,存放需要被執(zhí)行的外部函數(shù)
        private Queue<Action> _waitQueue;
        #endregion

        #region Event
        //自定義線程池的構(gòu)造函數(shù)
        public TaskPool()
        {
            _workingDictionary = new Dictionary<string, Task>();
            _freeQueue = new Queue<Task>();
            _waitQueue = new Queue<Action>();
            _threadCount = 10;

            Task task = null;
            //產(chǎn)生固定數(shù)目的線程
            for (int i = 0; i < _threadCount; i++)
            {
                task = new Task();
                //給每一個(gè)任務(wù)綁定事件
                task.WorkComplete += new Action<Task>(WorkComplete);
                //將每一個(gè)新創(chuàng)建的線程放入空閑隊(duì)列中
                _freeQueue.Enqueue(task);
            }
        }

        //線程任務(wù)完成之后的工作
        void WorkComplete(Task obj)
        {
            lock (this)
            {
                //將線程從字典中排除
                _workingDictionary.Remove(obj.Key);
                //將該線程放入空閑隊(duì)列
                _freeQueue.Enqueue(obj);

                //判斷是否等待隊(duì)列中有任務(wù)未完成
                if (_waitQueue.Count > 0)
                {
                    //取出一個(gè)任務(wù)
                    Action item = _waitQueue.Dequeue();
                    Task newTask = null;
                    //空閑隊(duì)列中取出一個(gè)線程
                    newTask = _freeQueue.Dequeue();
                    // 線程執(zhí)行任務(wù)
                    newTask._taskAction = item;
                    //把線程放入到工作隊(duì)列當(dāng)中
                    _workingDictionary.Add(newTask.Key, newTask);
                    //設(shè)置信號(hào)量
                    newTask.Active();
                    return;
                }
                else
                {
                    return;
                }
            }
        }

        //添加任務(wù)到線程池
        public void AddTaskItem(Action taskItem)
        {
            lock (this)
            {
                Task task = null;
                //判斷空閑隊(duì)列是否存在線程
                if (_freeQueue.Count > 0)
                {
                    //存在線程,取出一個(gè)線程
                    task = _freeQueue.Dequeue();
                    //將該線程放入工作隊(duì)列
                    _workingDictionary.Add(task.Key, task);
                    //執(zhí)行傳入的任務(wù)
                    task._taskAction = taskItem;
                    //設(shè)置信號(hào)量
                    task.Active();
                    return;
                }
                else
                {
                    //空閑隊(duì)列中沒有空閑線程,就把任務(wù)放到等待隊(duì)列中
                    _waitQueue.Enqueue(taskItem);
                    return;
                }
            }
        }
        #endregion
    }

解釋:這里的兩個(gè)方法,基本符合我的設(shè)想,注意每一個(gè)方法里面都有l(wèi)ock操作,這就保證了,多個(gè)線程進(jìn)行操作相同的隊(duì)列對(duì)象的時(shí)候,能夠進(jìn)行互斥。保證一個(gè)時(shí)間只有一個(gè)線程在操作。

測試代碼:

    class Program
    {
        static void Main(string[] args)
        {
            TaskPool _taskPool = new TaskPool();

            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            for (var i = 0; i < 20; i++)
            {
                _taskPool.AddTaskItem(Print);
            }
            Console.Read();
        }

        public static void Print()
        {
            Console.WriteLine("Do Something!");
        }
    }

這里我執(zhí)行了20次print操作,看看結(jié)果是啥:

從圖中看到20次確實(shí)執(zhí)行了,但是看不到線程是哪些,稍微修改一下自定義的線程池。

1.在自定義線程的構(gòu)造函數(shù)中添加:如下代碼,查看哪些線程被創(chuàng)建了

        public Task()
        {
            _thread = new Thread(Work);
            _thread.IsBackground = true;
            Key = Guid.NewGuid().ToString();
            //線程開始執(zhí)行
            _thread.Start();
            Console.WriteLine("Thread:"+_thread.ManagedThreadId+" has been created!");
        }

2.在線程完成工作方法之后添加如下代碼,查看哪些線程參與執(zhí)行任務(wù)

        private void Work()
        {
            while (true)
            {
                //判斷信號(hào)狀態(tài),如果有set那么 _locks.WaitOne()后的程序就繼續(xù)執(zhí)行
                _locks.WaitOne();
                _taskAction();
                Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId+"workComplete");
                //執(zhí)行事件
                WorkComplete(this);
            }
        }

3.修改客戶端程序

    class Program
    {
        static void Main(string[] args)
        {
            TaskPool _taskPool = new TaskPool();

            for (var i = 0; i < 20; i++)
            {
                _taskPool.AddTaskItem(Print);
            }
            Console.Read();
        }

        public static void Print()
        {
            Thread.Sleep(10000);
        }
    }

測試結(jié)果:

從結(jié)果可以看到,開始和執(zhí)行的線程都是固定的那10個(gè),所以這個(gè)程序是可用的。

到此這篇關(guān)于C#自定義線程池的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • c#之事件用法

    c#之事件用法

    這篇文章介紹了c#中事件的用法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • C#實(shí)現(xiàn)Word轉(zhuǎn)換TXT的方法詳解

    C#實(shí)現(xiàn)Word轉(zhuǎn)換TXT的方法詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)Word轉(zhuǎn)換TXT的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • .net 通過 WebAPI 調(diào)用nsfwjs 進(jìn)行視頻鑒別功能

    .net 通過 WebAPI 調(diào)用nsfwjs 進(jìn)行視頻鑒別功能

    這篇文章主要介紹了.net 通過 WebAPI 調(diào)用 nsfwjs 進(jìn)行視頻鑒別,文末給大家提到了FFMPEG獲取視頻關(guān)鍵幀并保存成jpg圖像的相關(guān)知識(shí),需要的朋友可以參考下
    2021-09-09
  • C#?wpf定義ViewModelBase進(jìn)行簡化屬性綁定

    C#?wpf定義ViewModelBase進(jìn)行簡化屬性綁定

    綁定機(jī)制是wpf的核心,也是界面獨(dú)立的根本,尤其是使用了mvvm模式,本文主要介紹了wpf如何定義ViewModelBase進(jìn)行簡化屬性綁定,需要的可以參考下
    2024-04-04
  • c# OpenCvSharp實(shí)現(xiàn)常見檢測(斑點(diǎn)檢測,輪廓檢測,邊緣檢測)

    c# OpenCvSharp實(shí)現(xiàn)常見檢測(斑點(diǎn)檢測,輪廓檢測,邊緣檢測)

    這篇文章主要為大家詳細(xì)介紹了c#如何使用OpenCvSharp實(shí)現(xiàn)常見檢測(斑點(diǎn)檢測,輪廓檢測,邊緣檢測),文中的示例代碼講解詳細(xì),需要的小伙伴可以參考下
    2023-12-12
  • 淺談C# StringBuilder內(nèi)存碎片對(duì)性能的影響

    淺談C# StringBuilder內(nèi)存碎片對(duì)性能的影響

    這篇文章主要介紹了淺談StringBuilder內(nèi)存碎片對(duì)性能的影響,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • C# DatagridView常用操作匯總

    C# DatagridView常用操作匯總

    這篇文章主要介紹了C# DatagridView常用操作匯總,羅列了一些常用的用法與技巧,需要的朋友可以參考下
    2014-07-07
  • c#中如何獲取指定字符前的字符串

    c#中如何獲取指定字符前的字符串

    這篇文章主要介紹了c#中如何獲取指定字符前的字符串問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • C#提取網(wǎng)頁中超鏈接link和text部分的方法

    C#提取網(wǎng)頁中超鏈接link和text部分的方法

    這篇文章主要介紹了C#提取網(wǎng)頁中超鏈接link和text部分的方法,涉及C#正則表達(dá)式及字符串操作相關(guān)技巧,需要的朋友可以參考下
    2016-02-02
  • C#命令行參數(shù)解析庫System.CommandLine使用

    C#命令行參數(shù)解析庫System.CommandLine使用

    System.CommandLine是一個(gè)基于.Net Standard 2.0的命令行參數(shù)解析庫,該項(xiàng)目還是屬于beta狀態(tài),期待以后的正式版本,文章通過示例代碼給大家介紹了System.CommandLine使用講解,感興趣的朋友一起看看吧
    2021-06-06

最新評(píng)論

巴中市| 久治县| 略阳县| 开阳县| 道真| 盘山县| 安塞县| 宁国市| 新营市| 竹山县| 怀来县| 重庆市| 怀远县| 甘孜县| 竹溪县| 彭山县| 辛集市| 大冶市| 贡嘎县| 阳城县| 崇义县| 丽江市| 洪洞县| 淄博市| 万源市| 渭南市| 彰化县| 彰武县| 克山县| 昌邑市| 北宁市| 宜兰市| 静乐县| 闵行区| 济阳县| 紫金县| 綦江县| 鹤山市| 海丰县| 安庆市| 汾阳市|