C# 스레드 풀 기능 자체 구현(1)

스레드 탱크의 기술적 배경


대상을 대상으로 프로그래밍을 할 때, 대상을 만들고 없애는 것은 시간이 많이 걸린다. 대상을 만들려면 메모리 자원이나 기타 더 많은 자원을 가져야 하기 때문이다.
그래서 서비스 프로그램의 효율을 높이는 한 수단은 대상을 창설하고 소각하는 횟수를 최대한 줄이는 것이다. 특히 자원을 많이 소모하는 대상의 창설과 소각이다.기존의 대상을 어떻게 이용하여 서비스를 하는가가 바로 해결해야 할 관건적인 문제이다. 사실 이것이 일부'지화자원'기술이 발생한 원인이다.예를 들어 모두가 익숙한 데이터베이스 연결 탱크는 바로 이 사상을 따라 생긴 것이다. 본고에서 소개한 스레드 탱크 기술도 이 사상에 부합된다.

스레드 탱크 기술은 어떻게 서버 프로그램의 성능을 향상시킬 것인가


내가 언급한 서버 프로그램은 고객의 요청을 받아들일 수 있고 처리할 수 있는 프로그램을 가리키며, 인터넷 고객의 요청을 받아들일 수 있는 네트워크 서버 프로그램만 가리키는 것이 아니다.
다중 스레드 기술은 주로 프로세서 단원 내의 여러 스레드가 집행되는 문제를 해결하는데 이것은 프로세서 단원의 유휴 시간을 현저하게 줄이고 프로세서 단원의 삼키기 능력을 증가시킬 수 있다.그러나 다중 루틴을 잘못 적용하면 한 작업에 대한 처리 시간이 늘어납니다.간단한 예를 들면 다음과 같습니다.
한 서버에서 작업을 완료하는 시간이 T라고 가정합니다.
     T1  
      T2  , 
      T3  

분명T=T1+T2+T3.이것은 극도로 간소화된 가설이므로 주의해라.
이를 통해 알 수 있듯이 T1은 다중 스레드 자체가 가져온 비용이다. 우리는 T1, T3이 사용하는 시간을 줄이고 T의 시간을 줄이기를 갈망한다.그러나 일부 스레드 사용자들은 이 점을 눈치채지 못했기 때문에 프로그램에서 빈번하게 스레드를 만들거나 폐기했기 때문에 T1과 T3는 T에서 상당한 비율을 차지했다.분명히 이것은 스레드의 약점(T1, T3)을 돋보이게 한 것이지, 장점(병발성)이 아니다.
스레드 풀 기술은 T1, T3의 시간을 단축하거나 조정하는 기술에 주목하여 서버 프로그램의 성능을 향상시키는 것이다.이것은 T1, T3을 서버 프로그램의 시작과 종료 시간대 또는 일부 빈 시간대에 배치하여 서버 프로그램이 고객의 요청을 처리할 때 T1, T3의 비용이 들지 않도록 한다.
스레드 풀은 T1, T3이 발생하는 시간대를 조정할 뿐만 아니라 스레드를 만드는 수를 현저히 감소시켰다.다음 예를 참조하십시오.
한 서버가 하루에 50000개의 요청을 처리하고, 요청마다 하나의 단독 라인이 필요하다고 가정하십시오.우리는 스레드 탱크 기술과 스레드 탱크 기술에 불리한 서버를 이용하여 이러한 요청을 처리할 때 발생하는 스레드 총수를 비교한다.온라인 스레드 탱크에서 스레드 수는 일반적으로 고정되어 있기 때문에 스레드 총수는 스레드 탱크의 스레드 수나 상한선(이하 스레드 탱크 사이즈라고 약칭)을 초과하지 않는다. 만약에 서버가 스레드 탱크를 이용하여 이러한 요청을 처리하지 않으면 스레드 총수는 50000이다.일반적인 스레드 탱크의 사이즈는 50000보다 훨씬 작다.따라서 스레드 탱크를 이용한 서버 프로그램은 50000을 만들기 위해 요청을 처리할 때 시간을 낭비하지 않고 효율을 높인다.
이것들은 모두 가설이기 때문에 문제를 충분히 설명할 수 없다. 다음에 나는 스레드 탱크의 간단한 실현을 토론하고 이 프로그램에 대해 비교 테스트를 해서 스레드 기술의 장점과 응용 분야를 설명할 것이다.

스레드 탱크의 간단한 실현 및 대비 테스트


일반적으로 간단한 스레드 탱크는 적어도 아래의 구성 부분을 포함한다.
스레드 풀 관리자(ThreadPoolManager): 스레드 풀을 생성하고 관리하는 데 사용워크스레드(WorkThread): 스레드 풀의 스레드작업 인터페이스(Task): 작업 스레드를 통해 작업을 스케줄링할 수 있도록 각 작업이 수행되어야 하는 인터페이스입니다.
작업 대기열: 처리되지 않은 작업을 저장합니다.완충 메커니즘을 제공하다.
이어서 나는 가장 간단한 연못을 보여 주었다.최적화된 것은 없습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;

namespace ThreadManager
{
    public class ThreadPoolManager
    {
        private int MaxThreadNum;
        private int MinThreadNum;
        private int GrowStepNum;
        // 
        public int ThreadNum{get;set;}
        // 
        public int DefaultThreadNum { get; set; }

        private Queue TaskQueue;
        private Queue WorkThreadList;

        public ThreadPoolManager(int i)
        {
            TaskQueue = new Queue();
            WorkThreadList = new Queue();
            DefaultThreadNum = 10;
            if (i > 0)
                DefaultThreadNum = i;
            CreateThreadPool(i);
        }
        public ThreadPoolManager():this(10)
        {
        }
        public bool IsAllTaskFinish()
        {
            return TaskQueue.Count == 0;
        }
        public void CreateThreadPool(int i)
        {
            if (WorkThreadList == null)
                WorkThreadList = new Queue();
            lock (WorkThreadList)
            {
                for (int j = 0; j < i;j++)
                {
                    ThreadNum++;
                    WorkThread workthread = new WorkThread(ref TaskQueue,ThreadNum);
                    WorkThreadList.Enqueue(workthread);
                }
            }
        }
        public void AddTask(Task task)
        {
           
            if (task == null)
                return;
            lock (TaskQueue)
            {
                TaskQueue.Enqueue(task);
            }
            //Monitor.Enter(TaskQueue);
            //TaskQueue.Enqueue(task);
            //Monitor.Exit(TaskQueue);
        }
        public void CloseThread()
        {
            //Object obj = null;
            while (WorkThreadList.Count != 0)
            {
                try
                {
                    WorkThread workthread = WorkThreadList.Dequeue();
                    workthread.CloseThread();
                    continue;
                }
                catch (Exception)
                {
                }
                break;
            }
        }
    }
}
워크스레드 클래스
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadManager
{
    public class WorkThread
    {
        public int ThreadNum { get; set; }
        private bool flag;
        private Queue TaskQueue;
        private Task task;
        public WorkThread(ref Queue queue, int i)
        {
            this.TaskQueue = queue;
            ThreadNum = i;
            flag = true;
            new Thread(run).Start();
        }
        public void run()
        {
            while (flag && TaskQueue != null)
            {
                // 
                lock (TaskQueue)
                {
                    try
                    {
                            task = TaskQueue.Dequeue();
                    }
                    catch (Exception)
                    {
                        task = null;
                    }
                    if (task == null)
                        continue;
                }
                try
                {
                    task.SetEnd(false);
                    task.StartTask();
                }
                catch (Exception)
                {
                }
                try
                {
                    if (!task.IsEnd())
                    {
                        task.SetEnd(false);
                        task.EndTask();
                    }
                }
                catch (Exception)
                {
                }

            }//end of while
        }
        public void CloseThread()
        {
            flag = false;
            try
            {
                if (task != null)
                    task.EndTask();
            }
            catch (Exception)
            {   
            }
        }
    }
}
task클래스와 실현클래스
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ThreadManager
{
    public interface Task
    {
        /// 
        /// set flag of task.
        /// 
        void SetEnd(bool flag);
        /// 
        /// start task.
        /// 
        void StartTask();
        /// 
        /// end task.
        /// 
        void EndTask();
        /// 
        /// get status of task.
        /// 
        /// 
        bool IsEnd();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadManager
{
    public class TestTask:Task
    {
        private bool is_end;
        public void SetEnd(bool flag)
        {
            is_end = flag;
        }
        public void StartTask()
        {
            Run();
        }
        public void EndTask()
        {
            is_end = true;
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":"+" !");
        }
        public bool IsEnd()
        {
            return is_end;
        }
        public void Run()
        {
            for (int i = 0; i < 1000; i++)
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":"+i);
            }
        }

    }
}

이 간단한 모델에 존재하는 문제점은 TASK를 얻는 것이 끊임없이 시도되고 성능을 떨어뜨리는 경우가 많다는 것이다. 개선해야 할 방법은 신호량을 늘리는 메커니즘으로 프로그램이 공전하지 않도록 하는 것이다!
다음 글에서 저는 최적화를 해서 스레드 탱크를 진정으로 효율을 높일 것입니다!

좋은 웹페이지 즐겨찾기