做项目的一点收获之一
前言
八月初接了个活,经过两个多月(中间有一个星期的时间去了趟郑州,还有段时间忙老师的项目报告)的学习和开发,现在终于接近尾声了。项目规模不大,但杂七杂八的要用到很多东西,其中有不少都是第一次接触到,着实让我头大了几回,在这里记下一点收获,以做日后参考之用(我得记性太差:-()。
使用线程
项目要求对内网和外网数据库进行同步,每个服务器都有若干数据库,每个数据库又包含若干数据表。一个办法是对每个要同步的数据表在其中一个服务器上进行查询,有更新就下载到本地,然后再上传到另一个服务器对应的数据表中,然后再对下一个数据表进行同样的操作,可想而知,这是多笨的办法。于是决定采用多线程,我写了一个数据表操作类,类中包含了每个线程需要的信息(包括连接信息、计数器、各种标志位等,当然得有下载和更新数据的方法),在主程序中对每个数据表生成一个该类的实例,每个实例对应四个线程(分别对应内网上传、下载和外网上传、下载),然后在到达更新周期时启动线程来完成同步操作。关于多线程的更多资料见[ZT]C#的多线程机制探索(1)。
但是,这样又带来了另一个问题:如果数据表很多,则同时启动的线程也会很多,创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。例如如果有100个表,那么最多同时启动的线程将达到400个,很难想象这时会是什么样的情况。
最后的解决办法是采用线程池。线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。默认情况下,每个进程可以产生25个线程池线程。然而,这个数量可以通过编辑mscoree.h文件中的CorSetMaxThreads成员加以改变。如果有额外的线程请求,这个请求将加入到队列中,直到某个线程完成了分配给它的任务,返回到线程池中为止,从而可以防止资源不足。
使用线程池有几种方法,我使用的是QueueUserWorkItem方法,该方法的使用方法如下:
callBack表示线程池中的线程执行任务时要调用的委托,state表示包含状态的对象,该对象将在线程执行任务时传递给委托。返回true表示方法调用成功。
因为是静态方法,所以在调用时不需要先声明线程池的实例。例如:
ThreadPool类中还有很多其他方法,目前还没用过,就不记了。
在使用线程时产生了一个疑问:使用线程池时传递给委托的方法要带一个object类型的参数,而在使用线程时传递给委托的方法不能带任何参数,线程池和线程的这点不同可以带来什么好处呢?以后要弄明白。
今天先扯这么多。