在C#中,我试图创建一个带有两个循环的Windows服务,这两个循环将以设定的间隔同时运行。例如,LoopA将每隔30秒运行一次,LoopB每5秒运行一次。
LoopA内部发生的任务可能需要30多个秒才能完成。如果发生这种情况,LoopA将立即重新开始,好像任务只需要20秒,LoopA将不会再运行10秒。
我已经实施了LoopA。我现在的问题是实现LoopB并行运行,其行为方式与LoopA相同,但间隔为5秒。这是我的LoopA代码,它在一个Thread中运行:
private Thread Worker;
private AutoResetEvent StopRequest;
private TimeSpan loop_a_freq;
private TimeSpan loob_b_freq;
public LoopManager(Thread _worker, AutoResetEvent _stopRequest)
{
// Threads
this.Worker = _worker;
this.StopRequest = _stopRequest;
RunLoopA();
}
private void RunLoopA()
{
DateTime start_current_loop = DateTime.Now;
DateTime next_loop = start_current_loop + loop_a_freq;
for (;;)
{
// Do processing here
new LoopAction();
DateTime now = DateTime.Now;
if (now > next_loop)
{
next_loop = now;
}
TimeSpan delay = next_loop - now;
Thread.Sleep(delay);
next_loop += loop_a_freq;
if (StopRequest.WaitOne(0))
{
return;
}
}
}
如何实施RunLoopB()
?线程是C#的一个方面,我从来没有完全探索过。我需要使用Parallel.For()
吗?
答案 0 :(得分:2)
这是一个你可以放入linqpad并测试的小片段。这将防止计时器重叠。基本上我们执行回调,停止计时器,处理一些工作,重置计时器并再次启动它。你需要一个计时器来完成每个定时任务。
要清楚,这将阻止您的线程不必要地排队,因为您只创建一个新线程来处理另一个完成后的工作。拥有2个计时器将允许您以不同的间隔运行2个不同的进程,从而创建自己的线程。同样,每个计时器只允许每个进程的一个实例发生。
基本流程
基本代码
private System.Timers.Timer _timer;
private int _delaySeconds = 5;
void Main()
{
// timer prevents threads from overlapping modify with care
_timer = new System.Timers.Timer();
_timer.Interval = _delaySeconds*1000;
_timer.AutoReset = true; // important to prevent overlap
_timer.Elapsed += OnProcess;
_timer.Start();
}
private void OnProcess(object sender, System.Timers.ElapsedEventArgs args)
{
// timer prevents from thread overlapping modify with care
_timer.Stop();
// do work
Debug.WriteLine("Processing on thread. [{0}]", Thread.CurrentThread.ManagedThreadId).Dump("this");
// setting the interval resets the timer
_timer.Interval = _delaySeconds*1000;
_timer.Start();
}
排查效果
另外,我昨天发现这篇文章可能对您有助于诊断线程性能。
答案 1 :(得分:2)
using System.Timers;
enum EventType {quit, task};
class LoopDaLoop {
Timer _30Seconds_publiser = new Timer(20000);
Timer _5Seconds_publisher = new Timer(5000);
Timer _terminator = new Timer(60000);
BlockingCollection<EventType> loopAEvents = new BlockingCollection<EventType>();
BlockingCollection<EventType> loopBEvents = new BlockingCollection<EventType>();
public LoopDaLoop() {
_30Seconds_publiser.Elapsed += _30Seconds_publiser_Elapsed;
_5Seconds_publisher.Elapsed += _5Seconds_publisher_Elapsed;
_terminator.Elapsed += _terminator_Elapsed;
_30Seconds_publiser.Start();
_5Seconds_publisher.Start();
_terminator.Start();
Task.Run(() => loopA());
Task.Run(() => loopB());
}
void _terminator_Elapsed(object sender, ElapsedEventArgs e) {
loopAEvents.Add(EventType.quit);
loopBEvents.Add(EventType.quit);
}
void _5Seconds_publisher_Elapsed(object sender, ElapsedEventArgs e) {
loopBEvents.Add(EventType.task);
}
void _30Seconds_publiser_Elapsed(object sender, ElapsedEventArgs e) {
loopAEvents.Add(EventType.task);
}
private void loopA() {
while (loopAEvents.Take() != EventType.quit) {
// decrypt wife's personal email
}
}
private void loopB() {
while (loopBEvents.Take() != EventType.quit) {
// navigate attack drones
}
}
}
答案 2 :(得分:1)
这似乎已经准备好了,但是为了让另一个线程运行,你需要并行启动第一个线程,第二个线程相同,并等待它们。使用Task
s代替Threads
可能会更容易,但此处使用Thread
s
public LoopManager(Thread _worker, AutoResetEvent _stopRequest)
{
// Threads
this.Worker = _worker;
this.StopRequest = _stopRequest;
var threadA = new Thread(RunLoopA);
var threadB = new Thread(RunLoopB);
// Start the loops
threadA.Start();
threadB.Start();
// Join the threads to avoid the program exiting before they're done
threadA.Join();
threadB.Join();
}
private void RunLoopB() {...} // As RunLoopA, but using the loop_b_freq variable
现在,如果您希望能够确保每个循环开始而不等待前一个过程完成,那么您将开始考虑System.Timers.Timer
class更好地服务的实现。请注意,在这种情况下还有不想使用的System.Threading.Timer
,因为它缺少事件模式。