多线程周期性执行的C#设计模式
我的C#Windows服务有以下要求多线程周期性执行的C#设计模式,c#,multithreading,design-patterns,thread-synchronization,periodic-processing,C#,Multithreading,Design Patterns,Thread Synchronization,Periodic Processing,我的C#Windows服务有以下要求 在服务启动时,它从数据库获取一组数据 并将其保存在内存中 具有从3个不同线程定期执行的业务逻辑 每个线程将使用步骤1中提到的数据收集中的不同数据子集执行相同的业务逻辑。每个线程将生成不同的结果集 如果数据收集发生任何更改,所有3个线程都将定期运行 当任何客户端调用服务时,服务应该能够返回线程执行的状态 我知道C#有不同的机制来实现周期性线程执行。 计时器、带睡眠的线程、事件WaitHandle等。, 我试图了解哪种线程机制或设计模式最适合此要求 最简单的解决
我试图了解哪种线程机制或设计模式最适合此要求 最简单的解决方案是在
Task Method()
样式中定义调度逻辑,并使用Task.Run()
执行它们,而在主线程中,只需使用Task.WaitAny()等待执行完成即可。如果任务已完成,您可以再次调用task.WaitAny
,但不调用已完成的任务,而是传递task.Delay(timeuntinextschedule)
。
这样,任务就不会阻塞主线程,并且可以避免仅仅为了等待而旋转CPU。通常,您可以避免在现代.NET中直接管理
根据其他要求,如标准化错误处理、监控能力、这些计划任务的管理,您还可以依赖更强健的解决方案,如。更现代的方法是使用任务,但请查看原则
namespace Test {
public class Program {
public static void Main() {
System.Threading.Thread main = new System.Threading.Thread(() => new Processor().Startup());
main.IsBackground = false;
main.Start();
System.Console.ReadKey();
}
}
public class ProcessResult { /* add your result state */ }
public class ProcessState {
public ProcessResult ProcessResult1 { get; set; }
public ProcessResult ProcessResult2 { get; set; }
public ProcessResult ProcessResult3 { get; set; }
public string State { get; set; }
}
public class Processor {
private readonly object _Lock = new object();
private readonly DataFetcher _DataFetcher;
private ProcessState _ProcessState;
public Processor() {
_DataFetcher = new DataFetcher();
_ProcessState = null;
}
public void Startup() {
_DataFetcher.DataChanged += DataFetcher_DataChanged;
}
private void DataFetcher_DataChanged(object sender, DataEventArgs args) => StartProcessingThreads(args.Data);
private void StartProcessingThreads(string data) {
lock (_Lock) {
_ProcessState = new ProcessState() { State = "Starting", ProcessResult1 = null, ProcessResult2 = null, ProcessResult3 = null };
System.Threading.Thread one = new System.Threading.Thread(() => DoProcess1(data)); // manipulate the data toa subset
one.IsBackground = true;
one.Start();
System.Threading.Thread two = new System.Threading.Thread(() => DoProcess2(data)); // manipulate the data toa subset
two.IsBackground = true;
two.Start();
System.Threading.Thread three = new System.Threading.Thread(() => DoProcess3(data)); // manipulate the data toa subset
three.IsBackground = true;
three.Start();
}
}
public ProcessState GetState() => _ProcessState;
private void DoProcess1(string dataSubset) {
// do work
ProcessResult result = new ProcessResult(); // this object contains the result
// on completion
lock (_Lock) {
_ProcessState = new ProcessState() { State = (_ProcessState.State ?? string.Empty) + ", 1 done", ProcessResult1 = result, ProcessResult2 = _ProcessState?.ProcessResult2, ProcessResult3 = _ProcessState?.ProcessResult3 };
}
}
private void DoProcess2(string dataSubset) {
// do work
ProcessResult result = new ProcessResult(); // this object contains the result
// on completion
lock (_Lock) {
_ProcessState = new ProcessState() { State = (_ProcessState.State ?? string.Empty) + ", 2 done", ProcessResult1 = _ProcessState?.ProcessResult1 , ProcessResult2 = result, ProcessResult3 = _ProcessState?.ProcessResult3 };
}
}
private void DoProcess3(string dataSubset) {
// do work
ProcessResult result = new ProcessResult(); // this object contains the result
// on completion
lock (_Lock) {
_ProcessState = new ProcessState() { State = (_ProcessState.State ?? string.Empty) + ", 3 done", ProcessResult1 = _ProcessState?.ProcessResult1, ProcessResult2 = _ProcessState?.ProcessResult2, ProcessResult3 = result };
}
}
}
public class DataEventArgs : System.EventArgs {
// data here is string, but could be anything -- just think of thread safety when accessing from the 3 processors
private readonly string _Data;
public DataEventArgs(string data) {
_Data = data;
}
public string Data => _Data;
}
public class DataFetcher {
// watch for data changes and fire when data has changed
public event System.EventHandler<DataEventArgs> DataChanged;
}
名称空间测试{
公共课程{
公共静态void Main(){
System.Threading.Thread main=新系统.Threading.Thread(()=>new Processor().Startup());
main.IsBackground=false;
main.Start();
System.Console.ReadKey();
}
}
公共类ProcessResult{/*添加结果状态*/}
公共类ProcessState{
public ProcessResult ProcessResult1{get;set;}
public ProcessResult ProcessResult2{get;set;}
public ProcessResult ProcessResult3{get;set;}
公共字符串状态{get;set;}
}
公共类处理器{
私有只读对象_Lock=新对象();
专用只读数据获取程序\u数据获取程序;
私有进程状态ProcessState;
公共处理器(){
_DataFetcher=新的DataFetcher();
_ProcessState=null;
}
公共无效启动(){
_DataFetcher.DataChanged+=DataFetcher\u DataChanged;
}
私有void DataFetcher_DataChanged(对象发送方,DataEventArgs args)=>StartProcessingThreads(args.Data);
私有void StartProcessingThreads(字符串数据){
锁{
_ProcessState=newProcessState(){State=“Starting”,ProcessResult1=null,ProcessResult2=null,ProcessResult3=null};
System.Threading.Thread one=新建System.Threading.Thread(()=>DoProcess1(数据));//将数据操作到一个子集
1.IsBackground=true;
一、启动();
System.Threading.Thread two=新的System.Threading.Thread(()=>DoProcess2(数据));//将数据操作到一个子集
2.IsBackground=true;
二、启动();
System.Threading.Thread three=新的System.Threading.Thread(()=>DoProcess3(数据));//将数据操作到一个子集
3.IsBackground=true;
三、开始;
}
}
public ProcessState GetState()=>\u ProcessState;
私有void DoProcess1(字符串数据子集){
//工作
ProcessResult=new ProcessResult();//此对象包含结果
//完工时
锁{
_ProcessState=new ProcessState(){State=(_-ProcessState.State??string.Empty)+“,1完成”,ProcessResult1=result,ProcessResult2=_-ProcessState?.ProcessResult2,ProcessResult3=_-ProcessState?.ProcessResult3};
}
}
私有void DoProcess2(字符串数据子集){
//工作
ProcessResult=new ProcessResult();//此对象包含结果
//完工时
锁{
_ProcessState=new ProcessState(){State=(_-ProcessState.State??string.Empty)+“,2完成”,ProcessResult1=_-ProcessState?.ProcessResult1,ProcessResult2=result,ProcessResult3=_-ProcessState?.ProcessResult3};
}
}
私有void DoProcess3(字符串数据子集){
//工作
ProcessResult=new ProcessResult();//此对象包含结果
//完工时
锁{
_ProcessState=new ProcessState(){State=(_-ProcessState.State??string.Empty)+“,3完成”,ProcessResult1=_-ProcessState?.ProcessResult1,ProcessResult2=_-ProcessState?.ProcessResult2,ProcessResult3=result};
}
}
}
公共类DataEventArgs:System.EventArgs{
//这里的数据是字符串,但可以是任何东西——只要考虑从3个处理器访问时的线程安全性就可以了
私有只读字符串_数据;
公共DataEventArgs(字符串数据){
_数据=数据;
}
公共字符串数据=>\u数据;
}
公共类数据获取程序{
//注意数据更改,并在数据更改时触发
public event System.EventHandler数据已更改;
}
}线程仅在数据更改时运行,或者线程会定期运行检测数据是否更改并处理?@Pratekshrivastava线程会定期运行并检测数据是否更改,然后处理业务逻辑。尽管如此,我不喜欢定期检查。我将使用IsBackground=True的线程;并自己实现逻辑。在这个场景中使用Task也是类似的,只需记住将Task标记为LongRunning@PrateekShrivastava谢谢你的来信