关于软件设计的一点感想3

本文探讨了在软件设计中,如何平衡响应时间、吞吐量、并发用户数和资源利用率,重点阐述了内存管理、多线程技术、数据存储策略及后期优化方法。详细分析了如何合理使用栈和堆,设计线程池,实现内存的高效利用。同时,介绍了数据存储优化、存储过程设计、数据库cache功能、集群和分布式数据库的应用。最后,强调了算法设计、代码重构、数据结构选择对于提高软件性能的重要性。

       软件设计中第三个应该考虑的因素则是软件的性能,性能的指标主要有软件响应时间、吞吐量、用户并发数和资源利用率。软件响应时间主要指系统对请求作出响应的时间,吞吐量指系统在单位时间内处理请求的数量,并发用户数是指系统可以同时承载的正常使用系统功能的用户的数量,资源利用率反映的是在一段时间内资源平均被占用的情况。

       性能要考虑如下几个因素:

     1、内存的使用

     2、多线程管理

     3、数据的存储

     4、后续的优化和重构

       程序代码内存有常量区、静态存储区、栈区、堆。一般影响其性能的主要有栈、堆。使用栈尽量避免使用超大的局部数据变量,注意函数调用的形参数据长度和数量,注意函数调用的深度,函数调用越深,压栈的数据也就越多尤其是递归函数的调用。在多线程技术中,线程都会有自己的线程来保存局部变量和函数调用的信息,所以线程多了,而总的内存空间又有限,平均下来就少了,所以栈空间要合理使用,避免栈数据越界的问题。而堆的申请和释放是个麻烦事情,在C++中主要由new和delete来操作内存,在C中主要由malloc和free来操作内存。在大批量需要用到堆空间申请和释放时需要用到RAII技术和引用技术,当一些变量需要频繁申请内存和释放内存就用RAII,即使用一个类来封装这些变量,在类构造函数中为这些变量申请内存,在类析构函数中为这些变量释放内存。引用技术就是当通过内存管理器分配到一块资源后对该内存块资源的合用标记加一,以后每当一个模块使用一次该资源就加一,用完后就减一,当减到为零时,由内存管理器去决定重复利用还是释放。

        一个进程当中有各种功能的线程,每一种功能的线程也许有很多个。线程的种类和数量之多,这对线程的管理与监控来说是件麻烦的事情。在这种情况下应当设计线程池管理器,专门来创建分配线程资源,回收释放线程资源,监控管理线程,控制线程数量等方面的工作,也同时多次复用线程资源,避免重复的创建和释放线程,提高系统整体效率。

如下面的代码:

class ITask
{
 public:
  void ProcessTask(unsigned long pUser);
};
//線程池
class CThreadPool
{
public:
 class ThreadInfo
 {
 public:
  ThreadInfo()
  {
   m_hThread=0;
   m_bBusyWorking=false;
  };
  ThreadInfo(HANDLE handle,bool bBusy)
  {
   m_hThread=handle;
   m_bBusyWorking=bBusy;
  }
  ThreadInfo(const ThreadInfo& info)
  {
   m_hThread=info.m_hThread;
   m_bBusyWorking=info.m_bBusyWorking;
  }
  HANDLE m_hThread;
  bool m_bBusyWorking;
 };
 typedef map<DWORD,ThreadInfo> ThreadInfoMap;
 typedef ThreadInfoMap::iterator Iterator_ThreadInfoMap;
 enum ThreadPoolStatus{STATUS_BUSY,STATUS_IDLE,STATUS_NORMAL};
 CRITICAL_SECTION m_CS;
 ThreadInfoMap m_threadMap;
 HANDLE m_hMgrIoPort;
 HANDLE m_hWorkerIoPort;
 HANDLE m_hMgrThread;
public:
 CThreadPool()
 {
  InitializeCriticalSection(&m_CS);
 }
 virtual ~CThreadPool()
 {
  DeleteCriticalSection(&m_CS);
 }
 void RemoveThread(DWORD dat)
 {
  Iterator_ThreadInfoMap Ite_thread;
  for(Ite_thread = m_threadMap.begin();Ite_thread != m_threadMap.end();Ite_thread++)
  {
   if(Ite_thread->first == dat)
   {
    m_threadMap.erase(Ite_thread);
   } 
  }
 }
 /*创建nStatic个线程封装到线程池中,创建一个管理线程并获得其句柄*/
 bool Start(unsigned short nStatic, unsigned short nMax)
 {
  if(nMax < nStatic)
  {
   return false;
  }
  HANDLE hThread;
  DWORD nThreadId;
  unsigned short m_nNumberOfStaticThreads = nStatic;
  unsigned short m_nNumberOfTotalThreads = nMax;
  //lock the resource
  EnterCriticalSection(&m_CS);
  //用于创建—个完成端口对象,将一个句柄同完成端口关联到一起。
  m_hMgrIoPort = CreateIoCompletionPort((HANDLE)INVALID_HANDLE_VALUE,NULL,0,0);
  hThread = CreateThread(
   NULL, // SD
   0, // initial stack size
   (LPTHREAD_START_ROUTINE)ManagerProc, // threadfunction
   (LPVOID)this, // thread argument
   0, // creationoption
   &nThreadId ); // thread identifier
  m_hMgrThread = hThread;
  //用于创建—个完成端口对象,将一个句柄同完成端口关联到一起。
  m_hWorkerIoPort = CreateIoCompletionPort((HANDLE)INVALID_HANDLE_VALUE,NULL,0,0);
  for(long n = 0; n < nStatic; n++)
  {
   hThread = CreateThread(
    NULL, // SD
    0, // initial stack size
    (LPTHREAD_START_ROUTINE)WorkerProc, // threadfunction
    (LPVOID)this, //thread argument
    0, //creation option
    &nThreadId );
   m_threadMap.insert(m_threadMap.end(),ThreadInfoMap::value_type(nThreadId,ThreadInfo(hThread,false)));
  }
  LeaveCriticalSection(&m_CS);
  return true;
 }
 /*停止所有线程*/
 void Stop(bool bHash = false)
 {
  EnterCriticalSection(&m_CS);
  WaitForSingleObject(m_hMgrThread,GetMgrWaitTime());
  CloseHandle(m_hMgrThread);
  CloseHandle(m_hMgrIoPort);
  //shut down all the worker threads
  UINT nCount=m_threadMap.size();
  HANDLE* pThread= new HANDLE[nCount];
  long n=0;
  ThreadInfo info;
  Iterator_ThreadInfoMap i = m_threadMap.begin();
  while(i != m_threadMap.end())
  {
   RemoveThread(i->first);
   info = i->second;
   pThread[n++] = info.m_hThread;
   i++;
  }
  DWORD rc=WaitForMultipleObjects(nCount,pThread,TRUE,30000);//wait for 0.5 minutes, then start to killthreads
  CloseHandle(m_hWorkerIoPort);
  if(rc >= WAIT_OBJECT_0 && rc <= nCount)
  {
   for(unsigned int n=0;n<rc;n++)
   {
    CloseHandle(pThread[n]);
   }
  }
  else if(rc==WAIT_TIMEOUT && bHash)
  {
   //some threadsnot terminated, we have to stop them.
   DWORD exitCode;
   for(unsigned int i=0; i<rc;i++)
   {
    if (::GetExitCodeThread(pThread[i],&exitCode) == STILL_ACTIVE)
    {
     TerminateThread(pThread[i],99);
    }
    CloseHandle(pThread[i]);
   }
  }
  delete[] pThread;
  LeaveCriticalSection(&m_CS);
 }
 void AddTask(void* pUser,ITask* pWorker)
 {
  ::PostQueuedCompletionStatus(m_hWorkerIoPort,reinterpret_cast<DWORD>(pWorker),reinterpret_cast<DWORD>(pUser),NULL);
 }
protected:
 HANDLE GetMgrIoPort()const
 {
  return m_hMgrIoPort;
 }
 UINT GetMgrWaitTime()const
 {
  return 1000;
 }
 HANDLE GetWorkerIoPort()const
 {
  return m_hWorkerIoPort;
 }
private:
 static DWORD WINAPI WorkerProc(void* p)
 {
  //convert the parameter to the server pointer.
  CThreadPool* pServer=(CThreadPool*)p;
  HANDLE IoPort = pServer->GetWorkerIoPort();
  unsigned long pN1,pN2;
  OVERLAPPED* pOverLapped;

  while(::GetQueuedCompletionStatus(IoPort,&pN1,&pN2,&pOverLapped,INFINITE))
  {
   ITask* pWorker = (ITask*)pN1;
   pWorker->ProcessTask(pN2);

  }
 }
 static DWORD WINAPI ManagerProc(void* p)
 {
  //convert the parameter to the server pointer.
  CThreadPool* pServer=(CThreadPool*)p;
  HANDLE IoPort = pServer->GetMgrIoPort();
  unsigned long pN1,pN2;
  OVERLAPPED* pOverLapped;

  while(::GetQueuedCompletionStatus(IoPort,&pN1,&pN2,&pOverLapped,INFINITE))
  {
   ITask* pWorker = (ITask*)pN1;
   pWorker->ProcessTask(pN2);
   
  }
 }
};

      数据的存储是个棘手的问题,但又是不得不考虑的问题,一般数据存储涉及到表关系的设计是否合理,对数据量大的表进行分表或表分区存储,对表数据建立合理的索引,通过多种索引联合检索的方式来提高查询效率,考虑表锁和表行锁的影响,其中例如这样一个查询:select * from table where id = 1,如果没有索引,必须遍历整个表,直到ID等于1的这一行被找到为止;有了索引之后(必须在ID这一列上建立的索引),在索引中查找,查找次数要少得多,索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,他能提高多行检索的速度,而非聚簇索引对于单行的检索很快,建立索引的目的是加快对表中记录的查找或排序,为表设置索引要付出的代价:一是增加了数据库的储存空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动),一般在这些列上要创建索引:1、在经常需要搜索的列上,可以加快搜索的速度,2、在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构,3、在外键上,可以加快连接的速度,在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的,4、在经常需要排序的列上创建索引,因为索引已经排序,这样的查询可以利用索引的排序,加快排序查询时间,5、在经常使用在where子句中的列上面创建索引,加快条件的判断速度。在代码中更应考虑存储过程设计的合理问题,还有就是开启数据库的cache功能,考虑数据库集群,分布式数据库等。

     后期的优化只要涉及到算法的设计和使用是否合理;模块对数据的处理流程合不合理,是否需要重构;在代码设计时运用良好的设计模式,减少代码冗余,提到代码复用率,现在流行的设计模式主要有23种,一共分三个类型,分别为创建型设计模式(与对象的创建有关,主要有抽象工厂、简单工厂、建造者、单例、原型)、结构型设计模式(处理类或对象的组合,主要有适配器,桥接、组合、装饰、享元、外观,代理)、行为型设计模式(对类或对象怎样交互和怎样分配职责进行描述,主要有职责链、命令、迭代器、解释器、状态、策略、备忘录、中介者、观察者、模板方法、访问者)。还有就是运用合理的数据结构,提高代码的效率。

   在设计高性能的软件系统时关键还是在于架构师和程序员的素质,如果各方面人员素质到位且协调合理,高性能的软件就能顺利诞生。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值