# Visual Basic > Visual Basic .NET > VS 2019 Dealing with a Loop & Milli/Nano Seconds

## digitaldrew

I'm not sure if this is the right place to be posting this because I don't believe it's related to the code I'm using. However, I'm not completely sure and if it isn't related to my code, then maybe someone can help me clarify where I need to be looking in order to resolve this. That being said, here is my issue..

I want my program to kickoff as close to 13:00:00.0000000 as possible. In order to achieve this, I'm running a loop that compares the current time with my desired time (13:00) and then starts the thread when it's reached..


```
Dim time As DateTime = DateTime.Now

While time.ToString("HH:mm:ss.fffffff") <= "13:00:00.0000000"
        time = DateTime.Now
End While

Thread1.RunWorkerAsync()
```

The code works well and is being ran on a large dedicated server (16 cores) with minimal processes/resources running. But the number of nanoseconds between the loop and when my thread kicks off seems to vary just a bit. For example, in one test my thread might start at 13:00:00.0078229 and if I test a couple hours later it might be 13:00:00.0002273 and then at another time it might be 13:00:00.0143383..After running several tests over several days it seems that the thread always kicks off between .000 and .014. My goal is to always have this loop run and start my thread between the .000 and .003 range.

What might be the cause in this fluctuation? I run the same loop on the same bare Windows server at different times of the day and one time it might start my thread at 13:00:00.0002273 and at another it starts at 13:00:00.0143383... Also, what might I need to look at or change so that I know it will start at .000 every single time?

I hope my post and issue have made some sense...

----------


## OptionBase1

Out of curiosity, have you debugged your code to see what the value of "time" is for several consecutive loop iterations?  If not, you should, and you'll likely find that the precision you are expecting just isn't happening.  You'll likely see that you will get many, many consecutive "duplicate" "time" values, and then the value of "time" will likely jump by a larger delta than you might expect.

Good luck.

Edit:  The below link is regarding C#, but the solutions suggested should be easily adapted to VB.NET

https://stackoverflow.com/questions/...-now-precision

----------


## Shaggy Hiker

I'm a bit surprised that you say the loop you have has minimal processes, though minimal resources makes sense. It's a total busy wait, which has horrible impacts...though only on one core of your system, so you might not notice. If that busy wait is only running for a few seconds out of every day, then it won't be so bad. If that loop is running continuously, then you can be certain that it is costing you money, if nothing else. Busy waits suck energy because the CPU core (though only one) would be running as fast as it possibly can, and doing nothing. The difference in electricity consumption for a busy wait is measurable. I had a thread on that over in General Developer a few years back. 

As it stands, you are getting a date, turning it into a string, then comparing it to another string. That doesn't make much sense. The DateTime has Hour, Minute, Second, and so on down to Nanosecond properties. Comparing those would be more effective than doing the string conversion and comparison. It likely won't solve your problem, though.

Things interrupt your loop. Preemptive multithreading at the OS level facilitates that. It means that precise timing generally isn't going to happen. Of course, the way you wrote the code, you aren't triggering anything "as close to" the time, you are triggering anything "as soon after" the time, which is not the same thing. What you are probably seeing is the vagaries of a preemptive multithreading OS. 

I'm not sure what the purpose of such precise triggering is, but some kind of external hardware signal might be necessary if you need to be more precise than what you are getting.

----------


## digitaldrew

Thanks for taking the time to respond @OptionBase1 and @Shaggy Hiker

@OptionBase1 - I have logged the iterations before and yes, there are lots of times when I will see multiple checks at the same 'time'..I will check the link you sent, thanks!

@Shaggy Hiker - Sorry, I probably should have been a little more specific when mentioning the minimal processes/resources. What I meant by that was there is nothing else running on the server but this program (and the things Windows runs in the background). No Microsoft One Drive, Skype, ..things like that which might load and utilize additional resources. We are looking to run this loop only once per week and it never runs for more than a minute. If it counts for anything, our server also has hyperthreading.

I'm running the loop "equal to or after" the time because when trying to do an exact match down to the millisecond it won't work most of the time. For example, if I try this code:


```
While Not String.Equals(time.ToString("HH:mm:ss.fffffff"), "13:00:00.0000000")
```

or


```
While time.ToString("HH:mm:ss.fffffff") <> "13:00:00.0000000"
```

Most of the time it won't work, and I'm guessing this is because like @OptionBase1 mentioned, there can be skips. As of now my thread always starts between .000 and .014...I just want to get that variance down to something like .000 and .003 if possible, but sounds like it might not be.

I'm going to have a look at that post you sent @OptionBase1 - thanks again!

----------


## Delaney

going under the milisecond with windows is very hard if not almost impossible. to do that you need to take account of the treatment time of each command. Well you have to do that even above the milisecond

For example, on an Arduino (which is much more simple in term of command than a PC and windows)  I had to make a loop with a cycle of 250micro second and get an info on an input. Finally I understood that the info on the input take 5 microsecond to get so I had to create a loop of 245microsecond in order to have a cycle of 250microsecond. 

I think you have something similar here with also the disadvantage of windows dealing by itself the priorities of treatment...

----------


## Shaggy Hiker

You kind of missed the points I was making. 

1) Doing a string comparison is a waste of time. You have the datetime as a datetime, which has properties for the different parts. You can compare numbers, and you really do want to do that rather than comparing strings. Yes, there's a bit more code, because you'd be comparing .Hours = 13 AndAlso Minutes = 0 AndAlso..etc, but those AndAlso are very efficient, as are integer comparisons. That way you save the cost of the string conversion and comparison...which won't save you much, but if you are dealing in nanoseconds, it might be something.

2) I understand WHY you did the >=, but it's still not the best you could do. You said it kicks off between 000 and 014. That suggests that it varies by +- 014, but you don't know in which way. It might have checked at 12.59.99999999999, and since that was less than 13.0.000000000000, it didn't run, but the next check was at 13.00.014, at which point it DOES run. You passed on the earlier check, even though it was closer to your target time than the next check turned out to be.

There will be variation around the target time. Perhaps switching to integer comparisons will reduce that variation and perhaps it won't. The OS is preemptive multitasking, so your process might be swapped out at any time, which means that you can't have perfect timing on that hardware with that OS. So, if you want to be as close as possible, and your variation is .0014 then you need to be checking for:

>= 12.59.9986

Otherwise, you won't be as close as possible.

----------


## OptionBase1

Shaggy, the OP's clunky method of determination and comparison in this case is just a red herring.  Fixing any of that won't change anything.  If you don't believe me, in a test project, try this:

Add a Button and a ListBox

In the Button_Click event, add this code:



```
Dim i as Integer

For i = 1 to 10000
  ListBox.Items.Add(DateTime.Now.ToString("HH:mm:ss.fffffff"))
Next
```

You will not see 10000 distinct "timestamps".  You will not see 1000 distinct timestamps. You will see a few distinct timestamps that are "duplicated".  And not duplicated because the code runs so fast that the time is literally the same to 7 decimal places, because if you examine the delta from when it changes from one timestamp to another, you will see that the size of the delta is relatively large, meaning there are huge "gaps" between consecutive "available" timestamps.  Much larger than the precision that the OP is looking for, so the method the OP is using will not work for the precision sought.

Edited to add:
That's not to say I disagree with either of your posts at all, the issues you point out are quite problematic as far as the busy loop, String comparison, etc.

----------


## dbasnett

Wonder if this might get closer on a more consistent basis.  All the caveats about being preemptive still apply.




```
    Private Async Function ThirteenHundredWait() As Task(Of Boolean)
        Dim stpw As New Stopwatch
        Const waitMSinTicks As Long = TimeSpan.TicksPerMillisecond * 20L
        Dim ThirteenHundred As TimeSpan = TimeSpan.FromHours(13.0#)
        Dim NowTS As TimeSpan
        Dim until13 As Long
        Dim finalTicks As Long
        Dim t As Task
        t = Task.Run(Sub()
                         NowTS = DateTime.Now.TimeOfDay ' to test ->  TimeSpan.FromHours(13.001#) '  to test -> TimeSpan.FromHours(12.995#) ' DateTime.Now.TimeOfDay
                         If NowTS > ThirteenHundred Then
                             until13 = (NowTS - ThirteenHundred).Ticks + TimeSpan.TicksPerDay
                         ElseIf NowTS < ThirteenHundred Then
                             until13 = (ThirteenHundred - NowTS).Ticks
                         Else
                             Exit Sub
                         End If
                         stpw.Start()
                         Do While stpw.Elapsed.Ticks < until13
                             finalTicks = until13 - stpw.Elapsed.Ticks
                             If finalTicks > waitMSinTicks Then
                                 Threading.Thread.Sleep(10)
                             End If
                         Loop
                         '13:00:00.00???????
                         finalTicks = stpw.Elapsed.Ticks
                         'Thread1.RunWorkerAsync()
                     End Sub)
        Await t
    End Function
```

----------


## Shaggy Hiker

> Shaggy, the OP's clunky method of determination and comparison in this case is just a red herring.  Fixing any of that won't change anything.  If you don't believe me, in a test project, try this:
> 
> Add a Button and a ListBox
> 
> In the Button_Click event, add this code:
> 
> 
> 
> ```
> ...


Oh, I don't doubt you. I've certainly never looked into timing anything anywhere near that precise. I've always assumed it was impossible. I felt it was impossible because of how preemptive multitasking works, but it sounds like you are talking about yet another issue even above that one.

----------


## vbdotnut

Instead of a do while maybe Do Until = your exact precision. Though I think you maybe chasing a wild goose. I have to say, I always appreciate looking at dba's solutions, so thanks for that anyway...

----------


## OptionBase1

> Instead of a do while maybe Do Until = your exact precision. Though I think you maybe chasing a wild goose. I have to say, I always appreciate looking at dba's solutions, so thanks for that anyway...


An analogy for what the OP is trying to accomplish:

You have a camera focused on an old fashioned wall clock that is universally accurate.  The camera is attached to monitoring equipment that is configured to read the time from the clock.  The goal is to get the monitoring equipment to then start a motor at precisely 0.07218 seconds after midnight.  Well, guess what, the wall clock second hand doesn't smoothly sweep through 360 degrees of rotation each minute, it moves by 6 degrees every second, and then sits still for a second, repeat.  So how does the monitoring equipment know when an exact fraction of a second has passed simply by looking at the clock?  It doesn't, because the precision of this clock is 1 second.

In the same way, the precision of DateTime.Now is larger than the OP's desired 0.003 seconds.  My testing reflects similar results that the OP reported, that the delta between one timestamp and the next closest timestamp is around 0.014 to 0.015 seconds.  So, relying strictly on DateTime.Now won't give the OP what they want, regardless of the type of loop, logic used, method of comparison, etc.

----------


## Shaggy Hiker

> an old fashioned wall clock that is universally accurate.


The first and second parts of this phrase do not go together.

Though it is otherwise a very good analogy.

----------


## vbdotnut

> An analogy for what the OP is trying to accomplish:


Right... i think the only thing in existence with this level of precision is a pulsar

----------


## Delaney

Atomic clock have this level of precision (about 10^-11 second)

----------

