记录下来待以后重用,多线程windows服务
工作项配置:

/// <summary> /// 工作项配置 /// </summary> public abstract class ServiceConfig { #region 子类必需实现的抽象属性 /// <summary> /// 工作项说明 /// </summary> public abstract string Description { get; } /// <summary> /// 工作项是否开启 /// </summary> public abstract string Enabled { get; } /// <summary> /// 工作项程序集 /// </summary> public abstract string Assembly { get; } /// <summary> /// 工作项执行间隔时间 /// </summary> public abstract int Interval { get; } #endregion #region 扩展属性 //可扩展 #endregion }
工作项:

/// <summary> /// 工作项 /// </summary> public abstract class ServiceJob { //配置对象 private ServiceConfig mConfigObject; //下次运行时间 private DateTime mNextTime; //任务是否在运行中 protected bool mIsRunning; /// <summary> /// 构造函数 /// </summary> public ServiceJob() { //变量初始化 this.mNextTime = DateTime.Now; this.mIsRunning = false; } /// <summary> /// 配置对象 /// </summary> public ServiceConfig ConfigObject { get { return this.mConfigObject; } set { this.mConfigObject = value; } } /// <summary> /// 开始工作 /// </summary> public void StartJob() { if (this.mConfigObject != null && this.mNextTime != null) { if (this.mConfigObject.Enabled.ToLower() == "true") { if (DateTime.Now >= this.mNextTime) { if (!this.mIsRunning) { this.mNextTime = DateTime.Now.AddSeconds((double)this.mConfigObject.Interval); this.Start(); } } } } } /// <summary> /// 停止工作 /// </summary> public void StopJob() { this.mConfigObject = null; this.mNextTime = DateTime.Now; this.mIsRunning = false; this.Stop(); } #region 子类必需实现的抽象成员 /// <summary> /// 开始工作 /// </summary> protected abstract void Start(); /// <summary> /// 停止工作 /// </summary> protected abstract void Stop(); #endregion }
工具类:

/// <summary> /// 工具类 /// </summary> public class ServiceTools : System.Configuration.IConfigurationSectionHandler { /// <summary> /// 获取AppSettings节点值 /// </summary> /// <param name="key"></param> /// <returns></returns> public static string GetAppSetting(string key) { return ConfigurationManager.AppSettings[key].ToString(); } /// <summary> /// 获取configSections节点 /// </summary> /// <returns></returns> public static XmlNode GetConfigSections() { XmlDocument doc = new XmlDocument(); doc.Load(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath); return doc.DocumentElement.FirstChild; } /// <summary> /// 获取section节点 /// </summary> /// <param name="nodeName"></param> /// <returns></returns> public static NameValueCollection GetSection(string nodeName) { return (NameValueCollection)ConfigurationManager.GetSection(nodeName); } /// <summary> /// 停止Windows服务 /// </summary> /// <param name="serviceName">服务名称</param> public static void WindowsServiceStop(string serviceName) { System.ServiceProcess.ServiceController control = new System.ServiceProcess.ServiceController(serviceName); control.Stop(); control.Dispose(); } /// <summary> /// 写日志 /// </summary> /// <param name="path">日志文件</param> /// <param name="cont">日志内容</param> /// <param name="isAppend">是否追加方式</param> public static void WriteLog(string path, string cont, bool isAppend) { using (StreamWriter sw = new StreamWriter(path, isAppend, System.Text.Encoding.UTF8)) { sw.WriteLine(DateTime.Now); sw.WriteLine(cont); sw.WriteLine(""); sw.Close(); } } /// <summary> /// 实现接口以读写app.config /// </summary> /// <param name="parent"></param> /// <param name="configContext"></param> /// <param name="section"></param> /// <returns></returns> public object Create(object parent, object configContext, System.Xml.XmlNode section) { System.Configuration.NameValueSectionHandler handler = new System.Configuration.NameValueSectionHandler(); return handler.Create(parent, configContext, section); } }
Service:

public partial class Service1 : ServiceBase { //用哈希表存放任务项 private Hashtable hashJobs; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { WriteLog.WriteMessage("Info", "runJobs_启动服务_" + DateTime.Now.ToString()); //启动服务 this.runJobs(); } protected override void OnStop() { WriteLog.WriteMessage("Info", "stopJobs_停止服务_" + DateTime.Now.ToString()); //停止服务 this.stopJobs(); } #region 自定义方法 private void runJobs() { try { WriteLog.WriteMessage("Info", "runJobs_加载工作项_" + DateTime.Now.ToString()); //加载工作项 if (this.hashJobs == null) { hashJobs = new Hashtable(); //获取configSections节点 XmlNode configSections = Base.ServiceTools.GetConfigSections(); foreach (XmlNode section in configSections) { //过滤注释节点(如section中还包含其它节点需过滤) if (section.Name.ToLower() == "section") { //创建每个节点的配置对象 string sectionName = section.Attributes["name"].Value.Trim(); string sectionType = section.Attributes["type"].Value.Trim(); //程序集名称 string assemblyName = sectionType.Split(',')[1]; //完整类名 string classFullName = assemblyName + ".Jobs." + sectionName + ".Config"; //创建配置对象 Base.ServiceConfig config = (Base.ServiceConfig)Assembly.Load(assemblyName).CreateInstance(classFullName); //创建工作对象 Base.ServiceJob job = (Base.ServiceJob)Assembly.Load(config.Assembly.Split(',')[1]).CreateInstance(config.Assembly.Split(',')[0]); job.ConfigObject = config; //将工作对象加载进HashTable this.hashJobs.Add(sectionName, job); } } } WriteLog.WriteMessage("Info", "runJobs_执行工作项_" + DateTime.Now.ToString() + " hashJobs.Keys.Count:" + this.hashJobs.Keys.Count); //执行工作项 if (this.hashJobs.Keys.Count > 0) { foreach (Base.ServiceJob job in hashJobs.Values) { //插入一个新的请求到线程池 if (System.Threading.ThreadPool.QueueUserWorkItem(threadCallBack, job)) { //方法成功排入队列 WriteLog.WriteMessage("Info", "runJobs_方法成功排入队列_" + DateTime.Now.ToString() + " Description:" + job.ConfigObject.Description); } else { //方法排入队列失败 WriteLog.WriteMessage("Info", "runJobs_方法排入队列失败_" + DateTime.Now.ToString() + " Description:" + job.ConfigObject.Description); } } } } catch (Exception error) { WriteLog.WriteErorrLog("Error", error); } } private void stopJobs() { //停止 if (this.hashJobs != null) { this.hashJobs.Clear(); } } /// <summary> /// 线程池回调方法 /// </summary> /// <param name="state"></param> private void threadCallBack(Object state) { while (true) { ((Base.ServiceJob)state).StartJob(); //休眠1秒 Thread.Sleep(1000); } } #endregion }
AppConfig:

<configSections> <!--自定义工作项,name属性请与Jobs下的任务目录同名,会据此加载该任务的config对象--> <section name="JobIndustry" type="SouMaiService.Base.ServiceTools,SouMaiService"/> <section name="JobKey" type="SouMaiService.Base.ServiceTools,SouMaiService"/> </configSections> <JobKey> <add key="description" value="关键字缓存"/> <add key="enabled" value="true"/> <add key="assembly" value="SouMaiService.Jobs.JobKey.Job,SouMaiService"/> <add key="interval" value="345600000"/> </JobKey> <appSettings> <!--每个线程操作缓存的数据量 --> <add key="ThreadMaxCount" value="30000"/> <!--JobKey 线程的起始值 1 --> <add key="JobKeyStartID" value="2600000"/> <!--JobKey 线程的最大值 当此值为空值时 则表示不配置线程最大值 --> <add key="JobKeyEndID" value="2900000"/> </appSettings>
应用程序的主入口点:

static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); } }
WriteLog日志:

public class WriteLog { /// <summary> /// /// </summary> /// <param name="fileName">文件名</param> /// <param name="ex"></param> public static void WriteErorrLog(string fileName, Exception ex) { if (ex == null) return; //ex = null 返回 DateTime dt = DateTime.Now; // 设置日志时间 string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 时:分:秒 string logName = dt.ToString("yyyy-MM-dd"); //日志名称 string logPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, Path.Combine("log", fileName)); //日志存放路径 string log = Path.Combine(logPath, string.Format("{0}.log", logName)); //路径 + 名称 try { FileInfo info = new FileInfo(log); if (info.Directory != null && !info.Directory.Exists) { info.Directory.Create(); } using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8"))) { write.WriteLine(time); write.WriteLine(ex.Message); write.WriteLine("异常信息:" + ex); write.WriteLine("异常堆栈:" + ex.StackTrace); write.WriteLine("异常简述:" + ex.Message); write.WriteLine("\r\n----------------------------------\r\n"); write.Flush(); write.Close(); write.Dispose(); } } catch { } } /// <summary> /// /// </summary> /// <param name="fileName">文件名</param> /// <param name="message"></param> public static void WriteMessage(string fileName, string message) { //ex = null 返回 DateTime dt = DateTime.Now; // 设置日志时间 string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 时:分:秒 string logName = dt.ToString("yyyy-MM-dd"); //日志名称 string logPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, Path.Combine("log", fileName)); //日志存放路径 string log = Path.Combine(logPath, string.Format("{0}.log", logName)); //路径 + 名称 try { FileInfo info = new FileInfo(log); if (info.Directory != null && !info.Directory.Exists) { info.Directory.Create(); } using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8"))) { write.WriteLine(time); write.WriteLine("信息:" + message); write.WriteLine("\r\n----------------------------------\r\n"); write.Flush(); write.Close(); write.Dispose(); } } catch { } } public static void WriteErorrLog(Exception ex, string message) { if (ex == null) return; //ex = null 返回 DateTime dt = DateTime.Now; // 设置日志时间 string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 时:分:秒 string logName = dt.ToString("yyyy-MM-dd"); //日志名称 string logPath = System.AppDomain.CurrentDomain.BaseDirectory; //日志存放路径 string log = Path.Combine(Path.Combine(logPath, "log"), string.Format("{0}.log", logName)); //路径 + 名称 try { FileInfo info = new FileInfo(log); if (info.Directory != null && !info.Directory.Exists) { info.Directory.Create(); } using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8"))) { write.WriteLine(time); write.WriteLine(ex.Message); write.WriteLine("异常信息:" + ex); write.WriteLine("异常堆栈:" + ex.StackTrace); write.WriteLine("异常简述:" + message); write.WriteLine("\r\n----------------------------------\r\n"); write.Flush(); write.Close(); write.Dispose(); } } catch { } } public static void WriteMessage(string message) { //ex = null 返回 DateTime dt = DateTime.Now; // 设置日志时间 string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 时:分:秒 string logName = dt.ToString("yyyy-MM-dd"); //日志名称 string logPath = System.AppDomain.CurrentDomain.BaseDirectory; //日志存放路径 string log = Path.Combine(Path.Combine(logPath, "log"), string.Format("{0}.log", logName)); //路径 + 名称 try { FileInfo info = new FileInfo(log); if (info.Directory != null && !info.Directory.Exists) { info.Directory.Create(); } using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8"))) { write.WriteLine(time); write.WriteLine("信息:" + message); write.WriteLine("\r\n----------------------------------\r\n"); write.Flush(); write.Close(); write.Dispose(); } } catch { } } }
线程使用:

namespace SouMaiService.Jobs.JobKey { public class Config : Base.ServiceConfig { #region 基本属性 private string mDescription; private string mEnabled; private string mAssembly; private int mInterval; /// <summary> /// 说明 /// </summary> public override string Description { get { return this.mDescription; } } /// <summary> /// 是否开启 /// </summary> public override string Enabled { get { return this.mEnabled; } } /// <summary> /// 处理程序集 /// </summary> public override string Assembly { get { return this.mAssembly; } } /// <summary> /// 间隔时间 /// </summary> public override int Interval { get { return this.mInterval; } } #endregion #region 构造函数 /// <summary> /// 构造函数,将配置项加载进对象 /// </summary> public Config() { NameValueCollection nvc = Base.ServiceTools.GetSection("JobKey"); foreach (string s in nvc.Keys) { switch (s.ToLower()) { //基本 case "description": this.mDescription = nvc[s].ToString(); break; case "enabled": this.mEnabled = nvc[s].ToString(); break; case "assembly": this.mAssembly = nvc[s].ToString(); break; case "interval": this.mInterval = int.Parse(nvc[s].ToString()); break; } } } #endregion } }

using System; using System.Collections.Generic; using System.IO; using System.Text; namespace SouMaiService.Jobs.JobKey { public class Job : Base.ServiceJob { /// <summary> /// 任务开始 /// </summary> protected override void Start() { try { //运行中 this.mIsRunning = true; //执行工作项 this.executeLogic(); } catch (Exception error) { //异常日志 WriteLog.WriteErorrLog("JobKey" + DateTime.Now.ToString("yyyy_MM_dd"), error); //发生异常时停止服务程序 Base.ServiceTools.WindowsServiceStop("SouMaiService"); } finally { //空闲 this.mIsRunning = false; } } /// <summary> /// 任务停止 /// </summary> protected override void Stop() { this.mIsRunning = false; } /// <summary> /// 执行逻辑 /// </summary> private void executeLogic() { InsertRedis bll = new InsertRedis(); int minKeyID = int.Parse(Base.ServiceTools.GetAppSetting("JobKeyStartID"));//起始ID int count = 0; //因数据可被删除 所以需要取出来最大的 KeyID - 起始值 count = bll.GetMaxKeyId() - minKeyID; //count = bll.GetKeyCount(); //每次线程缓存的数据间隔最大值 int maxCount = int.Parse(Base.ServiceTools.GetAppSetting("ThreadMaxCount")); //向上取整 int num = int.Parse(Math.Ceiling((double)count / (double)maxCount).ToString()); int preNum = minKeyID; for (int i = 1; i <= num; i++) { object ids = preNum.ToString() + "^" + (preNum + maxCount).ToString(); //线程池 System.Threading.ThreadPool.QueueUserWorkItem(SetKeyRedis, ids); //bll.SetKeyRedis(preNum, preNum + maxCount); preNum = preNum + maxCount; } } private void SetKeyRedis(object ids) { InsertRedis bll = new InsertRedis(); int beginId = int.Parse(ids.ToString().Split('^')[0]); int endId = int.Parse(ids.ToString().Split('^')[1]); bll.SetKeyRedis(beginId, endId); } } }