.NET / C #에서 틱 정밀도의 타임 스탬프를 얻는 방법은 무엇입니까?
지금까지 나는 DateTime.Now
타임 스탬프를 얻는 데 사용 했지만 DateTime.Now
루프로 인쇄 하면 약의 descrete 점프로 증가한다는 것을 알았 습니다. 15ms 그러나 내 응용 프로그램의 특정 시나리오에서는 가능한 한 가장 정확한 타임 스탬프를 얻어야합니다. 가급적이면 틱 (= 100ns) 정밀도를 사용합니다. 어떤 아이디어?
최신 정보:
분명히 StopWatch
/ QueryPerformanceCounter
는 갈 길이지만 시간을 측정하는 데만 사용할 수 있으므로 DateTime.Now
응용 프로그램이 시작될 때 호출 하고 StopWatch
실행 한 다음에서 StopWatch
반환 된 초기 값에 경과 시간을 추가하는 것에 대해 생각하고있었습니다 DateTime.Now
. 적어도 정확한 상대 타임 스탬프를 제공해야합니다. 그것에 대해 어떻게 생각하세요 (해킹)?
노트:
StopWatch.ElapsedTicks
와 다릅니다 StopWatch.Elapsed.Ticks
! 나는 1 tick = 100 ns라고 가정하고 전자를 사용했지만,이 경우 1 tick = 1 / StopWatch.Frequency
. 따라서 DateTime에 해당하는 틱을 얻으려면 StopWatch.Elapsed.Ticks
. 나는 이것을 어려운 방법으로 배웠다.
노트 2:
StopWatch 접근 방식을 사용하여 실시간과 동기화되지 않는 것으로 나타났습니다. 약 10 시간 후, 5 초 앞섰습니다. 그래서 저는 X가 1 시간, 30 분, 15 분 등이 될 수있는 X 정도마다 재 동기화해야한다고 생각합니다. 재 동기화 할 때마다 오프셋이 변경 될 수 있기 때문에 재 동기화를위한 최적의 시간이 얼마인지 잘 모르겠습니다. 최대 20ms.
DateTime.Now
읽는 시스템 시계의 값은 15ms 정도 (또는 일부 시스템에서는 10ms)마다 업데이트되므로 시간이 해당 간격을 중심으로 양자화됩니다. 코드가 다중 스레드 OS에서 실행되고 있다는 사실로 인해 발생하는 추가 양자화 효과가 있으므로 응용 프로그램이 "살아 있지"않고 따라서 실시간 현재 시간을 측정하지 않는 확장이 있습니다.
매우 정확한 타임 스탬프 값을 찾고 있기 때문에 (임의의 기간 타이밍이 아니라) Stopwatch
클래스 자체는 필요한 작업을 수행하지 않습니다. 나는 당신이 일종의 DateTime
/ Stopwatch
하이브리드로 이것을 직접해야한다고 생각합니다 . 응용 프로그램이 시작되면 현재 DateTime.UtcNow
값 (즉, 응용 프로그램이 시작될 때 대략적인 해결 시간)을 저장 한 다음 다음 Stopwatch
과 같이 객체 도 시작합니다 .
DateTime _starttime = DateTime.UtcNow;
Stopwatch _stopwatch = Stopwatch.StartNew();
그런 다음 고해상도 DateTime
값 이 필요할 때마다 다음 과 같이 얻을 수 있습니다.
DateTime highresDT = _starttime.AddTicks(_stopwatch.Elapsed.Ticks);
또한 _starttime 및 _stopwatch를 주기적으로 재설정하여 결과 시간이 시스템 시간과 너무 많이 동기화되지 않도록 할 수 있습니다 (실제로 이런 일이 발생하는지 확실하지 않으며 어쨌든 발생하는 데 오랜 시간이 걸립니다). .
업데이트 : 스톱워치 가 시스템 시간 (시간당 0.5 초 정도)과 동기화 되지 않는 것으로 보이 므로 DateTime
확인을 위해 호출 사이에 걸리는 시간을 기준으로 하이브리드 클래스 를 재설정하는 것이 합리적이라고 생각합니다. 시간:
public class HiResDateTime
{
private static DateTime _startTime;
private static Stopwatch _stopWatch = null;
private static TimeSpan _maxIdle =
TimeSpan.FromSeconds(10);
public static DateTime UtcNow
{
get
{
if ((_stopWatch == null) ||
(_startTime.Add(_maxIdle) < DateTime.UtcNow))
{
Reset();
}
return _startTime.AddTicks(_stopWatch.Elapsed.Ticks);
}
}
private static void Reset()
{
_startTime = DateTime.UtcNow;
_stopWatch = Stopwatch.StartNew();
}
}
일정한 간격 (매시간 등)으로 하이브리드 타이머를 재설정하면 미니어처 일광 절약 시간 문제와 같이 마지막 읽기 시간 이전으로 시간을 되돌릴 위험이 있습니다.
고해상도 틱 수를 얻으려면 정적 Stopwatch.GetTimestamp () 메서드를 사용하십시오.
long tickCount = System.Diagnostics.Stopwatch.GetTimestamp();
DateTime highResDateTime = new DateTime(tickCount);
.NET 소스 코드를 살펴보십시오.
public static long GetTimestamp() {
if(IsHighResolution) {
long timestamp = 0;
SafeNativeMethods.QueryPerformanceCounter(out timestamp);
return timestamp;
}
else {
return DateTime.UtcNow.Ticks;
}
}
[수락 된 답변은 스레드로부터 안전하지 않은 것으로 보이며 자체 승인으로 인해 타임 스탬프가 중복 될 수 있으므로 시간이 거꾸로 이동할 수 있으므로이 대체 답변]
실제로 관심이있는 것이 (댓글에 따라) 엄격한 오름차순으로 할당되고 시스템 시간에 최대한 가깝게 해당하는 고유 한 타임 스탬프 인 경우 다음 대체 방법을 시도 할 수 있습니다.
public class HiResDateTime
{
private static long lastTimeStamp = DateTime.UtcNow.Ticks;
public static long UtcNowTicks
{
get
{
long orig, newval;
do
{
orig = lastTimeStamp;
long now = DateTime.UtcNow.Ticks;
newval = Math.Max(now, orig + 1);
} while (Interlocked.CompareExchange
(ref lastTimeStamp, newval, orig) != orig);
return newval;
}
}
}
이러한 제안은 모두 너무 어려워 보입니다! Windows 8 또는 Server 2012 이상을 사용 GetSystemTimePreciseAsFileTime
하는 경우 다음과 같이 사용 하세요.
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)]
static extern void GetSystemTimePreciseAsFileTime(out long filetime);
public DateTimeOffset GetNow()
{
long fileTime;
GetSystemTimePreciseAsFileTime(out fileTime);
return DateTimeOffset.FromFileTime(fileTime);
}
이것은 DateTime.Now
어떤 노력도하지 않는 것보다 훨씬 더 정확 합니다.
자세한 내용은 MSDN 참조 : http://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx
운영 체제에 알려진 가장 정확한 날짜와 시간을 반환합니다.
The operating system also provides higher resolution timing through QueryPerformanceCounter
and QueryPerformanceFrequency
(.NET Stopwatch
class). These let you time an interval but do not give you date and time of day. You might argue that these would be able to give you a very accurate time and day, but I am not sure how badly they skew over a long interval.
1). If you need high resolution absolute accuracy: you can't use DateTime.Now
when it is based on a clock with a 15 ms interval (unless it is possible "slide" the phase).
Instead, an external source of better resolution absolute accuracy time (e.g. ntp), t1
below, could be combined with the high resolution timer (StopWatch / QueryPerformanceCounter).
2). If you just need high resolution:
Sample DateTime.Now
(t1
) once together with a value from the high resolution timer (StopWatch / QueryPerformanceCounter) (tt0
).
If the current value of the high resolution timer is tt
then the current time, t
, is:
t = t1 + (tt - tt0)
3). An alternative could be to disentangle absolute time and order of the financial events: one value for absolute time (15 ms resolution, possibly off by several minutes) and one value for the order (for example, incrementing a value by one each time and store that). The start value for the order can be based on some system global value or be derived from the absolute time when the application starts.
This solution would be more robust as it is not dependent on the underlying hardware implementation of the clocks/timers (that may vary betweens systems).
This is too much work for something so simple. Just insert a DateTime in your database with the trade. Then to obtain trade order use your identity column which should be an incrementing value.
If you are inserting into multiple databases and trying to reconcile after the fact then you will be mis-calculating trade order due to any slight variance in your database times (even ns increments as you said)
To solve the multiple database issue you could expose a single service that each trade hits to get an order. The service could return a DateTime.UtcNow.Ticks and an incrementing trade number.
Even using one of the solutions above anyone conducting trades from a location on the network with more latency could possibly place trades first (real world), but they get entered in the wrong order due to latency. Because of this the trade must be considered placed at the database, not at users' consoles.
The 15 ms (actually it can be 15-25 ms) accuracy is based on the Windows 55 Hz/65 Hz timer resolution. This is also the basic TimeSlice period. Affected are Windows.Forms.Timer, Threading.Thread.Sleep, Threading.Timer, etc.
To get accurate intervals you should use the Stopwatch class. It will use high-resolution if available. Try the following statements to find out:
Console.WriteLine("H = {0}", System.Diagnostics.Stopwatch.IsHighResolution);
Console.WriteLine("F = {0}", System.Diagnostics.Stopwatch.Frequency);
Console.WriteLine("R = {0}", 1.0 /System.Diagnostics.Stopwatch.Frequency);
I get R=6E-08 sec, or 60 ns. It should suffice for your purpose.
I'd add the following regarding MusiGenesis Answer for the re-sync timing.
Meaning: What time should I use to re-sync ( the _maxIdle
in MusiGenesis answer's)
You know that with this solution you are not perfectly accurate, thats why you re-sync. But also what you implicitly want is the same thing as Ian Mercer solution's:
a unique timestamp that is allocated in strict ascending order
Therefore the amount of time between two re-sync ( _maxIdle
Lets call it SyncTime) should be function of 4 things:
- the
DateTime.UtcNow
resolution - the ratio of accuracy you want
- the precision level you want
- An estimation of the out-of-sync ratio of your machine
Obviously the first constraint on this variable would be :
out-of-sync ratio <= accuracy ratio
For example : I dont want my accuracy to be worst than 0.5s/hrs or 1ms/day etc... (in bad English: I dont want to be more wrong than 0.5s/hrs=12s/day).
So you cannot achieve a better accuracy than what the Stopwatch offer you on your PC. It depends on your out-of-sync ratio, which might not be constant.
Another constraint is the minimum time between two resync:
Synctime >= DateTime.UtcNow
resolution
Here accuracy and precision are linked because if you using a high precision (for example to store in a DB) but a lower accuracy, You might break Ian Mercer statement that is the strict ascending order.
Note: It seems DateTime.UtcNow may have a bigger default Res than 15ms (1ms on my machine) Follow the link: High accuracy DateTime.UtcNow
Let's take an example:
Imagine the out-of-sync ratio commented above.
After about 10 hours, it was ahead by 5 seconds.
Say I want a microsec precision. My timer res is 1ms (see above Note)
So point by point:
- the
DateTime.UtcNow
resolution : 1ms - accuracy ratio >= out-of-sync ratio, lets take the most accurate possible so : accuracy ratio = out-of-sync ratio
- the precision level you want : 1 microsec
- An estimation of the out-of-sync ratio of your machine : 0.5s/hour (this is also my accuracy)
If you reset every 10s, imagine your at 9.999s, 1ms before reset. Here you make a call during this interval. The time your function will plot is ahead by : 0.5/3600*9.999s eq 1.39ms. You would display a time of 10.000390sec. After UtcNow tick, if you make a call within the 390micro sec, your will have a number inferior to the previous one. Its worse if this out-of-sync ratio is random depending on CPU Load or other things.
Now let's say I put SyncTime at its minimum value > I resync every 1ms
Doing the same thinking would put me Ahead of time by 0.139 microsec < inferior to the precision I want. Therefore if I call the function at 9.999 ms, so 1microsec before reset I will plot 9.999. And just after I will plot 10.000. I will have a good order.
So here the other constraint is : accuracy-ratio x SyncTime < precision level , lets say to be sure because number can be rounded up that accuracy-ratio x SyncTime < precision level/2 is good.
The issue is resolved.
So a Quick recap would be :
- Retrieve your timer resolution.
- Compute an estimate of the out-of-sync ratio.
- accuracy ratio >= out-of-sync ratio estimate , Best accuracy = out-of-sync ratio
- Choose your Precision Level considering the following:
- timer-resolution <= SyncTime <= PrecisionLevel/(2*accuracy-ratio)
- The best Precision you can achieve is timer-resolution*2*out-of-sync ratio
For the above ratio (0.5/hr) the correct SyncTime would be 3.6ms, so rounded down to 3ms.
With the above ratio and the timer resolution of 1ms. If you want a one-tick Precision level (0.1microsec), you need an out-of-sync ratio of no more than : 180ms/hour.
In its last answer to its own answer MusiGenesis state:
@Hermann: I've been running a similar test for the last two hours (without the reset correction), and the Stopwatch-based timer is only running about 400 ms ahead after 2 hours, so the skew itself appears to be variable (but still pretty severe). I'm pretty surprised that the skew is this bad; I guess this is why Stopwatch is in System.Diagnostics. – MusiGenesis
So the Stopwatch accuracy is close to 200ms/hour, almost our 180ms/hour. Is there any link to why our number and this number are so close ? Dont know. But this accuracy is enough for us to achieve Tick-Precision
The Best PrecisionLevel: For the example above it is 0.27 microsec.
However what happen if I call it multiple times between 9.999ms and the re-sync.
2 calls to the function could end-up with the same TimeStamp being returned the time would be 9.999 for both (as I dont see more precision). To circumvent this, you cannot touch the precision level because it is Linked to SyncTime by the above relation. So you should implement Ian Mercer solution's for those case.
Please don't hesitate to comment my answer.
If need the timestamp to perform benchmarks use StopWatch which has much better precision than DateTime.Now.
참고URL : https://stackoverflow.com/questions/1416139/how-to-get-timestamp-of-tick-precision-in-net-c
'Development Tip' 카테고리의 다른 글
NSArray와 NSMutableArray의 차이점 (0) | 2020.11.30 |
---|---|
크롬의 선택 옵션 요소에 대한 클릭 이벤트 (0) | 2020.11.30 |
Python으로 Linux에서 파일 권한 확인 (0) | 2020.11.30 |
ListView를 사용하여 Android에서 설정 화면을 만드시겠습니까? (0) | 2020.11.30 |
파이썬에서 따옴표로 묶인 문자열의 구분 기호를 분할하지만 무시하는 방법은 무엇입니까? (0) | 2020.11.30 |