为什么Javascript的setInterval比C#的Timers.Timer更精确 [英] Why is Javascript's setInterval more precise than than C#'s Timers.Timer

查看:113
本文介绍了为什么Javascript的setInterval比C#的Timers.Timer更精确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C#服务器制作多人JavaScript游戏。我开始只使用JavaScript并使用setInterval作为游戏计时器来计算每个玩家每1000/60毫秒的位置,这完美地工作,一切都很顺利。现在我已将主游戏逻辑移动到C#中的服务器,并使用System.Timers.Timer,间隔为1000/60。我的游戏现在非常抖动,这是因为C#计时器在每15-30毫秒之间的任何地方被勾选。



我明白我可以使用多媒体计时器更精确,但这似乎很疯狂,javascript本身支持比C#更准确的计时器。也许我的电脑出了问题?



这是复制问题的代码:



C#

I am making a multi-player JavaScript game with a C# server. I started off with just JavaScript and using setInterval as the game timer to calculate the position of each player every 1000/60 milliseconds, which worked perfectly and everything was smooth. Now I have moved the main game logic to the server in C#, and am using System.Timers.Timer with an interval of 1000/60. My game is now really juddery and it is because the C# timer is getting ticked anywhere between every 15-30 milliseconds.

I understand that I could use the multimedia timer for more precision, but this seems crazy that javascript would natively support a timer more accurate than C#. Perhaps it's something wrong with my computer?

Here is the code to replicate the issue:

C#

using System;
using System.IO;
using System.Timers;

class Program
{
    static StreamWriter _writer;

    static void Main(string[] args)
    {
        using (var timer = new Timer(1000 / 60))
        using (_writer = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\TimerTest.csv"))
        {
            timer.Elapsed += timer_Elapsed;
            timer.Start();

            System.Threading.Thread.Sleep(10000);
        }
    }

    static DateTime _lastTick = DateTime.MinValue;
    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        if (_lastTick != DateTime.MinValue)
            _writer.WriteLine((e.SignalTime - _lastTick).TotalMilliseconds);

        _lastTick = e.SignalTime;
    }
}





和JavaScript.js



and JavaScript.js

function RunTest()
{
    var array = []
    var date;

    var id = setInterval(function ()
    {
        if (date !== undefined)
            array.push(new Date() - date);

        date = new Date();
    }, 1000 / 60);

    setTimeout(function ()
    {
        clearInterval(id);
        DrawGraph(array);
    }, 10000);
}

function DrawGraph(data)
{
    var width = 800;
    var height = 400;
    var padding = 50;
    var max = Math.max(d3.max(data), 20);

    var xScale = d3.scale.linear().domain([0, data.length - 1]).range([0, width]);
    var yScale = d3.scale.linear().domain([0, max]).range([height, 0]);
    var xAxis = d3.svg.axis().scale(xScale).ticks(5).tickFormat(function (d) { return Math.round(d / 60); }).orient('bottom');
    var yAxis = d3.svg.axis().scale(yScale).ticks(5).orient('left');

    var line = d3.svg.line().x(function (d, i) { return xScale(i); }).y(yScale);

    var svg = d3.select("#chart").append("svg:svg").attr("width", width + padding * 2).attr("height", height + padding * 2).append('svg:g').attr("transform", "translate(" + padding + "," + padding + ")");

    svg.append('svg:g').attr('transform', 'translate(0,' + height + ')').call(xAxis);
    svg.append('svg:g').call(yAxis);
    svg.append('svg:path').attr('d', line(data));
}



Index.html


Index.html

<!DOCTYPE html>
<html>
<head>
    <title>TimeoutTest</title>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script src="JavaScript.js"></script>
    <style>
        path {
            stroke:black;
            stroke-width:1;
            fill:none;
        }

        * {
            font-family: Helvetica;
        }
    </style>
</head>
<body onload="RunTest()">
    <div id="chart"></div>
</body>
</html>





C#生成一个.csv文件,我在excel中绘制了图表,并显示了JavaScript浏览器中的图表,以下是一些屏幕截图: http://imgur.com/cStf6IB [ ^ ]



我想我想知道是否有什么愚蠢的我错过了,或者我只是要处理它。如果是这样的话,我想我会尝试坚持这个''juddery'计时器并在JavaScript中进行插值,以便在客户端恢复平滑运动。



我在WPF中使用了CompositionTarget.Rendering来制作动画,这显然效果非常好,我们每隔16ms就打一次。显然,这不适用于服务器应用程序。



The C# generates a .csv file which I have graphed in excel, and the JavaScript displays a graph in browser, here are some screen captures: http://imgur.com/cStf6IB[^]

I guess I'm wondering if there's anything stupid I've missed or if I just have to deal with it. If so I think I'll try and stick to this 'juddery' timer and interpolate in the JavaScript to get back to smooth motion in the client.

On another note I have used CompositionTarget.Rendering for animation in WPF and this obviously works very well, we get a tick every 16ms. Obviously this isn't suitable for a server application though.

推荐答案

您正在解决经典的Windows计时器解决方案问题。扭曲。

默认情况下,Windows中的计时器分辨率为15.6ms,这意味着当您启动定期计时器,指定16.7ms的间隔时,您可能会在预期时间内准确地收到下一个事件它或延迟了多达15ms。这就解释了为什么你看到实际间隔达到32毫秒。



如上所述,15.6毫秒是默认的计时器分辨率,但它可以用于应用程序改变这个价值。您可能会问为什么默认值不是可能的最高分辨率(1ms),据我所知,主要原因是因为更高的分辨率会导致更高的CPU负载,这意味着更高的功耗,这再次意味着更高的电力便携式设备的成本和更短的电池寿命。

在此处阅读更多内容: http ://msdn.microsoft.com/en-us/windows/hardware/gg463266.aspx [ ^ ]



因此,定时器在JavaScript中的准确性不如C#,但是在你的情况下它似乎是因为你正在运行JavaScript的浏览器,将计时器分辨率设置为比默认值更精确,并且因为你在C#程序中没有做同样的事情,所以会产生混淆。

在此处阅读更多内容: http://www.nczonline.net/blog/2011/12/14/timer-resolution-in-browsers [ ^ ]



timeBeginPeriod() [ ^ ]用于更改应用程序中的计时器分辨率(调用 timeEndPeriod() [ ^ ]当你不再需要准确性时)我认为有一个.NET等价物,但我没有看到它,所以看起来你可能不得不使用P / Invoke。

有关详细信息,请参阅此处: http://stackoverflow.com/questions/15071359/how-to-set-timer-resolution-from -c-sharp-to-1-ms [ ^ ]







当我重新阅读我的解决方案时,我意识到我似乎建议更改计时器分辨率并在C#程序中继续使用常规计时器。这不是我的意图,我提到了 timeBeginPeriod()的想法,你可以尝试一下,看看是否能解决问题。



我建议您使用多媒体计时器,就像您在问题中提到的那样,但希望我的答案有助于解释您获得结果的原因。
[/编辑]





Soren Madsen
You are fighting the classic Windows timer resolution issue. With a twist.
By default, the timer resolution in Windows is 15.6ms, which means that when you start a periodic timer, specifying a 16.7ms interval, you might receive your next event exactly when you expect it or delayed by as much as 15ms. This explains why you are seeing actual intervals of up to 32ms.

As I mentioned above, the 15.6ms is the default timer resolution, but it is possible for an application to change that value. You may ask why the default is not the highest resolution possible (1ms) and as far as I can tell, the primary reason is because a higher resolution results in a higher CPU load, which translates into higher power usage, which again means higher electric cost and shorter battery life for portable devices.
Read more here: http://msdn.microsoft.com/en-us/windows/hardware/gg463266.aspx[^]

So, timers are not more accurate in JavaScript than in C#, but in your case it appears so because the browser you are running the JavaScript in, sets the timer resolution to a finer accuracy than the default and since you are not doing the same in your C# program, confusion sets in.
Read more here: http://www.nczonline.net/blog/2011/12/14/timer-resolution-in-browsers[^]

timeBeginPeriod()[^] is used for changing the timer resolution in an application (call timeEndPeriod()[^] when you no longer need the accuracy) and I thought there was a .NET equivalent, but I am not seeing it, so it looks like you might have to use P/Invoke.
For more on that, see here: http://stackoverflow.com/questions/15071359/how-to-set-timer-resolution-from-c-sharp-to-1-ms[^]



As I was re-reading my solution, I realized it seems I recommend changing the timer resolution and keep using regular timers in your C# program. That was not my intention, I mentioned the timeBeginPeriod() with the idea that you could try it out to see if that solved the problem.

I recommend that you do use the multimedia timers instead, just as you mentioned in your question, but hopefully my answer helps explain why you were getting your results.
[/EDIT]


Soren Madsen


是的我也可以在我的电脑上看到这种抖动效果,或者从USB数字电视调谐器录制节目时更加准确。现在已停止并且调谐器已被拔掉,定时器非常规则。



我看到SignalTime间隔为15.625ms或31.2ms,可以通过System.Diagnostics.Stopwatch确认方差是真实的。



如果您的计时器分辨率与我的相同,则间隔将是15.625ms的倍数,设置16ms(1000/60)将得到31.25 ms的(向上舍入)间隔。这是卸载系统的情况,但电视调谐器肯定会让事情变得有点混乱,而且令人惊讶的是'坏'的Timer.Elapsed事件是以比预期更短的间隔发射的(~16ms而不是~31ms),这不是很容易解释。



有趣的是,将定时器间隔设置在16以上,即17到31ms,可以得到~31ms的一致事件间隔,当然也可以是最短的事件间隔〜通过将定时器间隔设置为1到15来实现16ms。



当设置定时器间隔时,可以看到向上舍入和向下舍入间隔之间的相同抖动到一个刚好超过15.625的其他倍数的值,即32,47和63ms。在较高的倍数下,效果消失,如前所示,除非电视调谐器正在运行,否则没有抖动。



所以确认而不是解释,但至少你不是独自!



艾伦。



[晚编辑当mpeg2视频时,抖动效果也可以重现在Windows媒体播放器或VLC媒体播放器中播放]
Yes I can see this jittering effect on my computer too, or to be more accurate I could when a programme was being recorded from the USB digital TV tuner. Now that has stopped and the tuner has been unplugged the timer is quite regular.

I was seeing SignalTime intervals of either 15.625ms or 31.2ms and could confirm with the System.Diagnostics.Stopwatch that the variance was real.

If your timer resolution is the same as mine the intervals will be multiples of 15.625ms and setting 16ms (1000/60) will give a (rounded up) interval of 31.25 ms. This is the case on the unloaded system but the TV tuner certainly messes things up a bit and suprisingly the 'bad' Timer.Elapsed events are being fired at a shorter interval than expected (~16ms instead of ~31ms), something that is not easy to explain.

Interestingly setting a timer interval above 16, i.e. 17 to 31ms, gives consistent event intervals of ~31ms and of course the shortest possible event interval of ~16ms is achieved by setting the timer interval to between 1 and 15.

The same jittering between the rounded up and the rounded down interval was seen when the timer interval was set to a value just above other multiples of 15.625, i.e. 32, 47 and 63ms. At higher multiples the effect disappeared and as indicated before there is no jitter unless the TV tuner was operating.

So confirmation rather than explanation, but at least you're not alone!

Alan.

[LATE EDIT the jittering effect can also be reproduced when an mpeg2 video is played in either Windows media player or VLC media player]


可能因为C#定时器控件在服务器端工作所以它依赖于客户端请求(根据请求和响应所需的时间)触发事件)....

另一方面javascript的setinterval在客户端工作,这就是为什么它更精确..



希望它能为您的目的解决..



谢谢
May be Because C# timer control works on server-side so its dependent on client request (time it takes for request and response according to the triggered event)....
on the other hand javascript's setinterval works on client-side that's why its more precise..

Hope it solves for your purpose..

Thanks


这篇关于为什么Javascript的setInterval比C#的Timers.Timer更精确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆