I am using a System.Windows.Forms.Timer in my application which triggers a method that adds new data to four LiveCharts. The interval is set to 1000 ms. It works fine for like the first one or two minutes but then the interval gets bigger and bigger and after 10 minutes it triggers only every 15 seconds or so.
I have tried using different Timers without any luck. Might it be that the performance of the application/LiveCharts is just too bad and because the timer runs on the UI thread it has to wait for the application to be "ready"?
Thanks!
Timer setup
graphRefreshTimer = new System.Windows.Forms.Timer();
graphRefreshTimer.Interval = 1000;
graphRefreshTimer.Tick += new EventHandler(refreshUI);
graphRefreshTimer.Start();
refreshUI (basically just adding new ChartValues to the LiveCharts. Takes a maximum of 100 ms to run)
//...
B1VoltageValues.Add(new MeasureModel
{
DateTime = now,
Value = Convert.ToDouble(B1.Voltage) / 1000
});
B1CurrentValues.Add(new MeasureModel
{
DateTime = now,
Value = Convert.ToDouble(B1.Current) / 1000
});
B1ChargingCapacityValues.Add(new MeasureModel
{
DateTime = now,
Value = Convert.ToDouble(B1.getChargeCapIfTrue()) / 1000
});
B1DischargingCapacityValues.Add(new MeasureModel
{
DateTime = now,
Value = Convert.ToDouble(B1.getDischargeCapIfTrue()) / 1000
});
B1EnergyValues.Add(new MeasureModel
{
DateTime = now,
Value = Convert.ToDouble(B1.Energy) / 1000
});
//...
The solution to the problem was to use the LiveCharts.Geared package which can handle way more data that the standard one. No further freezes of the UI occured after using this package.
Related
I have this service which calls Notification() function every second. What this function does is it checks the time difference between lastupdated and DateTime.UtcNow and check if the Countdiff is greater than 1
If the above conditions is true then it checks if the AppGuid is already in the DB if it's not it inserts it and calls DoAction() function which sends a notification. Everything works fine till here.
The problem starts when the AppGuid is already in DB.
What I need is if AppGuid is already in DB then send notification every 15 Min, here I'm struggling with keeping track last time I send notification, I tried to compare last timestamp when it got updated and tried to compare the difference but it keeps sending notifications resulting spamming the pipeline.
I tried to keep elasped time with stopwatch class but the problem it waits for 15 min when app starts initially to send anything.
How do I send notification only once every 15 min?
public class DataGetService : DelegatingHandler, IHostedService
{
private Timer _timer;
Stopwatch stopwatch = new Stopwatch();
public Task StartAsync(CancellationToken cancellationToken)
{
stopwatch.Start();
_timer = new Timer(Heartbeat, null, 1000, 1000);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
//Timer does not have a stop.
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Heartbeat(object state)
{
_ = Notifications(TimeSpan.FromMinutes(15));
}
public async Task Notifications(TimeSpan period)
{
// Result array have: LastUpdated, CountDiff, AppGuid, AppName, Timestamp
foreach (var d in result)
{
var x = _DBcontext.TestEvents.FirstOrDefault(o => o.AppGuid == (Guid)d.AppGuid);
if (DateTime.UtcNow - d.LastUpdated <= TimeSpan.FromMinutes(30) && d.CountDiff > 1)
{
if (x == null)
{
DoAction();
_DBcontext.TestEvents.Add(new TestEvents
{
AppGuid = (Guid)d.AppGuid,
AppName = d.AppName,
Timestamp = DateTime.UtcNow
});
}
else
{ //This is useful if app have crashed or was not able to update in db, it will update the current timestamp.
if (DateTime.UtcNow - x.Timestamp >= TimeSpan.FromMinutes(30))
{
x.Timestamp = DateTime.UtcNow;
}
else
{
if (stopwatch.Elapsed <= period)
return;
DoAction();
x.Timestamp = DateTime.UtcNow;
}
}
}
}
await _DBcontext.SaveChangesAsync();
stopwatch.Restart();
}
}
I'd do it the same way I would lock a user out for 15 minutes if they tried their password too many times: rather than trying to use a date field that tracks when a record was last updated, have a dedicated field for when the next event should be raised. At the time you send the first notification, set it to a future date and only send a new notification when the date falls into the past (whereupon you set the date future again)
By using a "last updated" field you risk another notification if something else about the record changes. If you feel that it's not relevant to put the date in the table concerned, consider having a table just for notification event dates; all it needs is a GUID and a date, and then it can function for any object ID in any table in the database (if the GUIDs are unique) - "no sending information about entity with GUID x until time y" is an easy thing to code for in that case and the eventing system doesnt need to know anything about the entity it is reporting on. You can make the subsystems naively raise events every second if they want to, but the sending of notifications can only happen every X minutes, so all the interim notifications are quenched. This simplifies the system raising the messages too; it can just raise them and not care for the logic of whether they should actually be notified or not
For future answer seekers:
I have added futureTime variable which adds 15 min to the Timestamp from DB.
The interesting thing was when I compare with if(DateTime.UtcNow == futureTime) the condition never became true, reason what I have understood is I call this function every second during the execution somehow system was skipping the time resulting false condition.
To overcome this I took the difference (DateTime.UtcNow - futureTime) and also consider the tolerance of seconds.
if (DateTime.UtcNow - d.LastUpdated <= TimeSpan.FromMinutes(30) && d.CountDiff > 1)
{
if (x == null)
{
DoAction();
_DBcontext.TestEvents.Add(new TestEvents
{
AppGuid = (Guid)item.AppGuid,
AppName = item.AppName,
Timestamp = DateTime.UtcNow
});
}
//This is useful if app have crashed or was not able to update in db, it will update the current timestamp.
else if (DateTime.UtcNow - x.Timestamp >= TimeSpan.FromMinutes(30))
{
x.Timestamp = DateTime.UtcNow;
}
else
{
//This will set the notification date in future
DateTime dbtimestamp = x.Timestamp;
DateTime futureTime = dbtimestamp.AddMinutes(15);
if (((DateTime.UtcNow - futureTime) - TimeSpan.FromSeconds(1)).Duration() < TimeSpan.FromSeconds(1.0))
{
DoAction();
x.Timestamp = DateTime.UtcNow;
}
}
}
First of all, I have been started to studying the C# from 8 months ago and I'm not good at English. So I'm sorry if I say something that you cannot understand.
Now, I'm developing the application with C# that get percentage of CPU usage.
I want to get CPU usage that all of Cores every one sec. Then I used the PerformanceCounter Class and Processor Category. This is code I wrote.
private void GetCpuUsageEvery1sec(object sender, ElapsedEventArgs e)
{
int getValue = 0;
mProcessorCount = Environment.ProcessorCount;
mPerformanceCounter.CategoryName = "Processor";
mPerformanceCounter.CounterName = "% Processor Time";
mPerformanceCounter.InstanceName = "_TOTAL";
getValue = (int)Math.Truncate(mPerformanceCounter.NextValue());
mProcessorCpuUsage[mProcessorCount] = getValue; //I set TOTAL's usage in last of Array
Console.WriteLine(DateTime.Now.ToString());
Console.WriteLine("Core:TOTAL {0}%", mProcessorCpuUsage[mProcessorCount]);
for (int count = 0; count < mProcessorCount; count++)
{
mPerformanceCounter.InstanceName = count.ToString(); //this code is case
getValue = (int)Math.Truncate(mPerformanceCounter.NextValue());
mProcessorCpuUsage[count] = getValue;
Console.WriteLine("Core:{0} {1}%", count, mProcessorCpuUsage[count]);
}
Console.WriteLine();
}
I wrote the Method with Timer Class that start GetCpuUsageEvery1sec Method as Event, too.
However, in the Processor category (or Processor Time Counter), this counter throw 0 if I change the InstanceName.
So, I cannot get only 0 if I do the Method with Timer Class.
I think that if I want to get a correct CPU usage, I should make instances same at number of Core. (And many of user will use this application. So I cannot specify the number of Core in advance.)
In this situation, I cannot get other solution?
I'd advice you to use the WMI query:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_PerfFormattedData_PerfOS_Processor");
var cpuTimes = searcher.Get()
.Cast<managementobject>()
.Select(mo => new
{
Name = mo["Name"],
Usage = mo["PercentProcessorTime"]
}
)
.ToList();
Hook this one up with a timer and you'll be settled good, it is better then using a for loop for every core.
First off- this is a homework assignment. I'm supposed to go beyond what we have learned, so I thought of a WPM console application.
I did a lot of searching on Timers, but that's way too over my head for first semester.
So I found an easier way. The thing is, I want to be able to call some string and have the user type them in, and run a calculation in the end to determine their words per minute. I read that using Task.Factory.StartNew should let me run two methods.
class Program
{
static void Main( string[] args )
{
Timer go = new Timer( );
WordBank display = new WordBank( );
Task.Factory.StartNew(go.timer1_Tick);
Task.Factory.StartNew(display.LevelOneWords);
Console.ReadKey( );
}
}//end main
class Timer
{
public Timer()
{}
public void timer1_Tick( )
{
int seconds= 0;
DateTime dt = new DateTime( );
do
{
Console.Write("One minute timer: " + dt.AddSeconds(seconds).ToString("ss"));
Console.Write("\r");
seconds++;
Thread.Sleep(1000);
} while ( seconds< 60 );
}
}//end Timer
class WordBank
{
public WordBank()
{ }
public void LevelOneWords()
{
string easyWords = "the boy had so much fun at the park.";
Console.WriteLine("\n\n", easyWords);
Console.ReadKey( );
}
When I run the program the timer starts for a second and then is immediately replaced with the string. Am I using Task.Factory.StartNew incorrectly?
Instead of running a timer while they are typing (requiring two programs simultaneously), instead try getting the time when they initially start typing, the time when they end typing, and then do some division. IE:
static void Main()
{
// Displays WordBank
WordBank display = new WordBank();
var startTime = DateTime.Now;
// Let them type for X amount of time
var totalWords = TakeUserInputForXSeconds(45);
var endTime = DateTime.Now;
var wpm = totalWords / (endTime.Subtract(startTime).TotalMinutes);
}
For the TakeUserInputForXSeconds method, I would look at the information in this post: Stop running the code after 15 seconds
I tried to get the exact start and stop time of interfaces.GetIPv4Statistics().BytesReceived;.
NetworkInterface interfaces;
public Form1()
{
InitializeComponent();
if (NetworkInterface.GetIsNetworkAvailable())
{
interfaces = NetworkInterface.GetAllNetworkInterfaces()[0];
}
Stopwatch timer = Stopwatch.StartNew();
var time1 = DateTime.Now.ToString("HH:mm:ss:fff");
//timer stop function take how much time? how if not ignored?
timer.Stop();
TimeSpan timespan = timer.Elapsed;
//10ms for the conversion
Console.WriteLine("Convert take time {0:00}:{1:00}:{2:000}",
timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
var timeStartGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
var currentByteReceive = interfaces.GetIPv4Statistics().BytesReceived;
var timeEndGetStatisticAndConvert = DateTime.Now.ToString("HH:mm:ss:fff");
Console.WriteLine("Start:\t{0}\nBytes Received:\t{1}\nStop:\t{2}",
timeStartGetStatistic, currentByteReceive, timeEndGetStatisticAndConvert);
I use Stopwatch to get the time needed for DateTime.Now.ToString("HHmmss");
I thought the timeEndGetStatisticAndConvert is the time includes also the time for conversion to string.
but the result is
Convert take time 00:00:010
Start: 23:04:12:134
Bytes Received: 700116647
Stop: 23:04:12:134
The start and stop time is the same in resolution of 1ms!!
So Stopwatch show wrong elapsed timespan?
DateTime.Now.ToString() not function as imagine?
Or when we display the result of DateTime.Now.ToString(), it get the time first then it only convert to string? (obviously this is the answer and sorry for this logical error)
By the way, I verify this
Stopwatch timer = Stopwatch.StartNew();
var currentByteReceive1 = interfaces.GetIPv4Statistics().BytesReceived;
timer.Stop();
is 0ms....
So I wonder in C#, what is the SMALLEST time resolution that can be used to display current time and how to display it?
and finally the exact start and stop time of interfaces.GetIPv4Statistics().BytesReceived; is showed by this
Contradiction Happen Here!!!
The real function start time should be AFTER 10ms I get the first time but not BEFORE!!
And then I will have the start time larger than the end time!!!
//variable name change because the real situation
//should be Add POSITIVE timespan.Milliseconds but not Add NEGATIVE
var timeStartGetStatisticAndConvert = DateTime.Now.AddMilliseconds(-(timespan.Milliseconds)).ToString("HH:mm:ss:fff");
var currentByteReceive = interfaces.GetIPv4Statistics().BytesReceived;
var timeEndGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
Console.WriteLine("Start:\t{0}\nBytes Received:\t{1}\nStop:\t{2}",
timeStartGetStatisticAndConvert, currentByteReceive, timeEndGetStatistic);
Convert take time 00:00:010
//If change sign, Start: 23:04:14:124
Start: 23:04:12:124
Bytes Received: 700116647
Stop: 23:04:12:134
thanks. I will ask the contradiction part in another post.
As far as I know, DateTime.Ticks provides the smallest resolution of time in C#. Beyond that you'll need high resolution timers provided by the Windows API; they are normally used for media players (which require a very high precision timer).
That looks really complicated. It could be because of the format you are selecting for your DateTime ("HH:mm:ss:fff").
interfaces.GetIPv4Statistics().BytesReceived means `interfaces is already initialized and the data is already there, I believe (i.e. BytesReceived).
Basically, what you want is:
var start = DateTime.Now;
if (NetworkInterface.GetIsNetworkAvailable())
{
interfaces = NetworkInterface.GetAllNetworkInterfaces()[0];
}
var currentByteReceive = interfaces.GetIPv4Statistics().BytesReceived;
Console.WriteLine("Timespan: {0}", DateTime.Now - start);
If, that is, I understand what you are trying to do.
Try to use Elapsed or Tick propertie
Stopwatch timer = Stopwatch.StartNew();
var currentByteReceive1 = interfaces.GetIPv4Statistics().BytesReceived;
timer.Stop();
Console.WriteLine(timer.Elapsed);
It gives me this 00:00:00.0026059 (2,6 ms.)
public interface Event
{
Guid identifier;
Timestamp ts;
}
We're thinking of using Reactive Extensions for a rewrite of a problem at my financial firm.
The premise is that we get events identified by a Guid (stock symbol + uniqueness entropy embedded into it), a timestamp, and a Value field. These come at a high rate, and we cannot act on these objects until "at least" after X seconds (10 seconds), after which we have to act on them, and remove them from the system.
Think about it like two windows, an initial window of "10 seconds" (for example T0 to T10), where we identify all the unique events (basically, group by guid), then we look into the next "10 seconds", "secondary window" (T10-T20), to make sure we're implementing the policy of "at least" 10 seconds. From the "initial window", we remove all the events (because we've accounted for them), and then from the "secondary window", we remove the ones that occurred in the "initial window". And we keep on moving 10 second sliding windows, so now we're looking at window T20-T30, repeat and rinse.
How could I implement this in Rx, because it seems like the way to go.
If you can rely on the server clock and the timestamp in the message (that is, we're in 'real life' mode), and you're after a sliding 10 second delay as opposed to a jumping 10 second window, then you can just delay the events 10 seconds:
var events = new Subject<Event>();
var delayedEvents = events.Delay(TimeSpan.FromSeconds(10));
Checking for unique events etc is just a matter of adding them to a set of some sort:
var guidSet = new HashSet<Guid>();
delayedEvents.Do(e => guidSet.Add(e.identifier));
If you're problem is instead that you must wait 10 seconds and then process the last 10 seconds at once, then you just want to buffer for 10 seconds instead:
var bufferedEvents = events.Buffer(TimeSpan.FromSeconds(10));
bufferedEvents.Do(es => { foreach (var e in es) guidSet.Add(e.identifier); });
I haven't shown the example of a sliding 10 second window as I can't imagine that's what you want (events get processed more than once).
Now we get serious. Let's say you don't want to rely on wall time and instead want to use the time within your events to drive your logic. Assuming event is redefined as:
public class Event
{
public Guid identifier;
public DateTime ts;
}
Create the historical scheduler and feed the scheduled events from the original ones:
var scheduler = new HistoricalScheduler();
var driveSchedule = events.Subscribe(e => scheduler.AdvanceTo(e.ts));
var target = events.SelectMany(e => Observable.Timer(e.ts, scheduler).Select(_ => e));
Now you can simply use the regular Rx combinators on target instead of event, and just pass through the scheduler so they are triggered appropriately, for example:
var bufferedEvents = target.Buffer(TimeSpan.FromSeconds(10), scheduler);
Here's a simple test. Create a hundred events each 'virtually' 30 seconds apart but in real-time triggered every second:
var now = DateTime.Now;
var test = Enumerable.Range(0,99).Select(i =>
Scheduler.ThreadPool.Schedule(
TimeSpan.FromSeconds(i),
() => events.OnNext(new Event() {
identifier = Guid.NewGuid(),
ts = now.AddSeconds(i * 30)
})
)
).ToList();
Subscribe to it and ask for 60 seconds of buffered events - and actually receive 2 events every 2 'real' seconds (60 virtual seconds):
target.Select(e => String.Format("{0} {1}", e.identifier, e.ts.ToString()))
.Buffer(TimeSpan.FromSeconds(60), scheduler)
.Select(es => String.Join(" - ", es))
.DumpLive();