我的程序中有一个计数器,希望每10分钟重置为0。
预计我的程序将引发事件。这些事件与警告有关,这是由于资源使用过多或在我们的实验中超出测试场景而导致的,这将需要采取某些措施,例如以CSV格式转储一些与测试相关的数据以及Tiff格式的某些图。当事件计数器达到3时,将每1分钟生成一次Tiff文件。
但是由于Tiff文件的大小,我希望不要过度生产这些文件。因此,重置计数器将确保仅跟踪重复发生的事件以采取进一步的措施。
在不添加过多不必要细节的情况下,我的程序的主要结构如下:
class Program
{
static void Main(string[] args)
{
counter = 0;
using (an API)
{
// do something here, which may raise an event
while (event)
{
// take an action
counter++; // keeps track of events raised
}
if (counter > 3)
{
// take a specific action
}
else
{
// take action B
}
counter = 0; // reset counter every 10 minutes, by calling a timer or async method
// to keep the application going
System.Windows.Forms.Application.Run();
}
}
// a timer method() // to help me reset the counter
// or
// an Async method ResetCounter()
}
我试图通过创建计时器方法来启动计时器:
private static bool TimeCounter()
{
System.Timers.Timer _delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 100000;
_delayTimer.Enabled = true;
// _delayTimer.Elapsed += new ElapsedEventHandler(_delayTimer_Elapsed); // attempted to use an additional method as well that could get triggered after 10 mins but it gets too complicated
_delayTimer.Start();
// not sure how to set this timer to return a boolean true when time elapsed, rather than calling another method
_delayTimer.AutoReset = autoreset;
}
private static void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
ResetCounter(); // the method not created yet
}
但是,采用计时器方法,首先,我不确定如何使计时器在时间流逝时返回布尔值true, 其次,如果我的API在main方法中每次在程序经过if-else条件时都调用此方法,则这可能会再次重置计时器,而不会让前10分钟的计时器过去。
因此遇到异步等待,我觉得这对我来说可能是一个更好的选择,我可能会打电话给我(在Stackoverflow上见过这样的东西)来重置计数器?:
var result = Task.Run(async () => { return await myAsyncMethod(); }).Result;
我以前从未使用过async-await,因此不确定如何使用async-await来达到预期的结果。
答案 0 :(得分:3)
我只会和DateTime.Now
1)每当您重置计时器或第一次执行代码时,都要保存当前时间:
var lastReset = DateTime.Now;
2)检查lastReset
是否在10分钟或更早之前:
if(lastReset.AddMinutes(10) <= DateTime.Now)
{
counter = 0;
}
答案 1 :(得分:1)
如果您希望在10分钟后立即重置计数器,而不管此时发生了什么事情,那么您可以继续使用System.Timers.Timer
的想法。您对问题的评论表明这就是您想要的。
要使某个计时器到期时发生某些事情,请为Elapsed事件附加一个事件处理程序。我建议使用lambda表达式将处理程序创建为匿名函数,如下所示:
_delayTimer.Elapsed += (o,e) => { counter = 0; };
由于此代码引用了counter
,因此它必须位于counter
可用的位置。 (new ElapsedEventHandler
部分是不必要的,因为您将附加到事件,所以编译器会自动为您创建委托。)
使用object initializer syntax使代码更整洁,创建和配置Timer即可:
var delayTimer = new System.Timers.Timer
{
Interval = 600000, // 10 minutes is 10 * 60 * 1000 == 600000 ms
AutoReset = true, // makes the timer start over automatically
};
delayTimer.Elapsed += ((o, e) => { counter = 0; });
delayTimer.Start();
请注意,无需显式设置Timer的Enabled
属性,因为Start()
方法将为您完成此操作。
旁注:一件很酷的事情是,实际上声明counter
的位置无关紧要(只要在创建处理程序时可用)。这种匿名函数引用“外部”变量的结构会导致counter
上的“关闭”。在C#中,闭包使变量“共享”,这样,即使从声明该变量的作用域之外的位置调用该函数,该函数也可以访问该变量。换句话说,即使counter
是局部变量(尽管出于其他原因,这可能是不切实际的),该方法仍然有效。
using System;
using System.Timers;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
// Declare the counter somewhere
var counter = 0;
// Create timer
var delayTimer = new Timer
{
Interval = 5000, // Changed to 5 seconds for demo purposes
AutoReset = true,
};
// Create the event handler
delayTimer.Elapsed += ((o, e) =>
{
// Print counter value before resetting
Console.WriteLine($"[Timer elapsed] The counter has value {counter}, resetting it...");
counter = 0;
});
// Start the timer
delayTimer.Start();
// Now simulate doing other stuff while the timer is running...
Console.WriteLine("I'll be silently incrementing the counter at a random pace.");
Console.WriteLine("Every five seconds, the timer event handler will reset the counter " +
"right after telling you how far I got.");
var r = new Random();
while (true)
{
// Sleep for a random number of milliseconds (between 0 and 999)
var sleepLength = r.Next() % 1000;
System.Threading.Thread.Sleep(sleepLength);
// Increment the counter
counter++;
}
// Console output example (values will be random):
// I'll be silently incrementing the counter at a random pace.
// Every five seconds, the timer event handler will reset the counter right after telling you how far I got.
// [Timer elapsed] The counter has value 11, resetting it...
// [Timer elapsed] The counter has value 9, resetting it...
// [Timer elapsed] The counter has value 12, resetting it...
// [Timer elapsed] The counter has value 10, resetting it...
// [Timer elapsed] The counter has value 9, resetting it...
// [Timer elapsed] The counter has value 8, resetting it...
// [Timer elapsed] The counter has value 6, resetting it...
// [Timer elapsed] The counter has value 4, resetting it...
// [Timer elapsed] The counter has value 14, resetting it...
}
}
}
答案 2 :(得分:0)
另一种解决方案是使用Thread.Timer,如果需要精确的间隔,请使用@speschel建议的逻辑
static int counter = 0;
static void Main(string[] args)
{
Timer timer = new Timer(ResetCount, null, 0, 100000);
while (true)
{
//Event simulation
if (Console.ReadKey().Key == ConsoleKey.Enter)
{
Console.WriteLine("Event triggerd"); ;
counter++;
}
if (counter > 3)
{
Console.WriteLine("Take a specific action");
}
else
{
Console.WriteLine("Take action B");
}
Thread.Sleep(1000);
}
}
private static void ResetCount(object state)
{
counter = 0;
}
答案 3 :(得分:0)
real 问题在注释中:
这些事件与警告有关,这些警告是由于资源占用过多或实验中的测试场景不可用而引起的,这将需要采取某些措施,例如以CSV格式转储一些与测试相关的数据以及Tiff格式的某些图。当事件计数器达到3时,将每1分钟生成一次Tiff文件。
但是由于Tiff文件的大小,我希望不要过度生产这些文件。因此,重置计数器将确保仅跟踪重复发生的事件以采取进一步的措施。
处理事件流是Reactive Extensions的领域,可以作为NuGet包使用。 Rx处理事件流的方式与LINQ处理数据的方式相同。
假设我们有一个事件源,那么如果此代码每3分钟有10个以上的警告,则可以执行一项操作:
var warnings = eventSource
.Where(evt => evt.Level >= Level.Warning)
.Buffer(TimeSpan.FromMinutes(3))
.Where(evts => evts.Count > 10)
.Subscribe(evts => ProcessEvents(evts));
Buffer在3分钟的窗口中批量处理事件。 Where()
像LINQ的Where
一样过滤事件,并且只允许警告级别或更高的事件。以后,它仅允许具有10个以上警告的批次。
最终结果是仅在3分钟的窗口中有10个以上的警告时才调用ProcessEvents
。
源是实现IObservable的任何类。事件,任务或数据等可以转换为Observable。不管警告的来源是什么,如果它可以实现IObservable接口,则可以与Rx一起使用。
在最简单的情况下,Subject可用于实现简单的可观察对象,该对象仅在有人调用其OnNext
方法时才产生事件。人们通常对此不屑一顾,因为它有点像在需要LINQ查询时使用for
循环,但是它对演示如何使用Rx很有用:
var eventSource=new Subject<TestEvent>();
//Somewhere where warnings are raise
eventSource.OnNext(new TestEvent { Level = Level.Info });
...
eventSource.OnNext(new TestEvent { Level = Level.Warning });
Rx库提供了transform data, events, tasks等可观察对象的方法。例如,FromEventPattern
会将.NET模式转换为IObservable:
var eventSource= Observable.FromEventPattern(h => someClass.SomeEvent += h,
h => someClass.someEvent -= h);