setInterval 的这种行为是否意味着 Javascript 中的多线程行为?
在使用 javascript 时我注意到了这个事情。你可以使用,
var i=0;
var startingTime=new Date().getTime();
setInterval("foo()",1);
function foo() {
i+=1;
if ($("#foodiv").text()==i) {
//we detected a doubled value (parallel execution)
$("#repdiv").append("[repetition on "+i+"]");
}
$("#foodiv").html(i);
$("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));
}
但当我阅读并尝试自己时,时间不是 1ms ,它至少是 10ms 或其他。事实上,10 秒后,我的 i 值约为 2300/2400 ,而不是预期的 10000 。
这是该过程的最小可能时间因素???当然不。如果我尝试这样做:
<html><head>
<script language="javascript" type="text/javascript" src="jquery-1.4.min.js"></script>
<script type="text/javascript">
var i=0;
var startingTime=new Date().getTime();
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
function foo() {
i+=1;
if ($("#foodiv").text()==i) {
//we detected a doubled value (parallel execution)
$("#repdiv").append("[repetition on "+i+"]");
}
$("#foodiv").html(i);
$("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));
}
</script>
</head>
<body>
<div id="foodiv"></div> (counter)
<br/>
<div id="timediv"></div> (seconds passed)
<br/>
<div id="repdiv"></div>
<br/>
</body>
</html>
计数器会走得非常快,10 秒后,我的值为 12000!!!!。这对我来说是无法解释的,因为调用不是并行执行的(或者至少我们可以为不同的调用提供一些双倍的 i 读取值,在repdiv div 中计算)。
有人能给我解释一下吗?我知道所有这些调用给CPU带来了很大的压力,但至少它令人惊讶地加快了速度。
我阅读了您在论坛中的所有回复和其他任务,它们证实了我的想法。但真正的问题是为什么!为什么他们将限制设置为 15 毫秒,而我可以执行多个连续调用,获得的时间要低得多?我确信这个多重回调系统不是一个好的做法,但我可以做到,而且我可能会使 CPU 负载饱和。
In using javascript i noticed this thing. You can use
var i=0;
var startingTime=new Date().getTime();
setInterval("foo()",1);
function foo() {
i+=1;
if ($("#foodiv").text()==i) {
//we detected a doubled value (parallel execution)
$("#repdiv").append("[repetition on "+i+"]");
}
$("#foodiv").html(i);
$("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));
}
but as i read and try myself the time is not 1ms , it's at least 10ms or something. In fact after 10 seconds, i have a value of i around 2300/2400 , and not 10000 as expected.
This is the minimum possible time factor for the procedure ??? certainly NO. If i try this :
<html><head>
<script language="javascript" type="text/javascript" src="jquery-1.4.min.js"></script>
<script type="text/javascript">
var i=0;
var startingTime=new Date().getTime();
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
function foo() {
i+=1;
if ($("#foodiv").text()==i) {
//we detected a doubled value (parallel execution)
$("#repdiv").append("[repetition on "+i+"]");
}
$("#foodiv").html(i);
$("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));
}
</script>
</head>
<body>
<div id="foodiv"></div> (counter)
<br/>
<div id="timediv"></div> (seconds passed)
<br/>
<div id="repdiv"></div>
<br/>
</body>
</html>
The counter will go very fast, and after 10 seconds, i have a value of 12000 !!!!. That's for me is unexplicable, because the call is not executed in parallel (or at least we could have some doubled readed values of i for different calls, figuring in the repdiv div).
Can someone explain me that ? I know the cpu is very stressed by all those calls, but at least it speed up things surprisingly.
I read all your responses and the other quests in the forum, and they confirmed my thinking. But the real question is Why ! Why they set the limit to 15ms when i can do multiple sequential calls obtaining a time much lower ? I'm sure this multiple callback system is not good practice, but i can do it, and i potentially can saturate cpu load.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不,Javascript 是单线程的。当您运行
setInterval
或setTimeout
时,会生成一个事件,然后将其添加到浏览器的执行队列中。因此,虽然您无法保证代码本身在您希望运行时准确运行,但您可以确定每次应该生成事件时都会生成该事件。因此,在本例中,您有 12 个事件,它们的生成时间非常接近。我注意到您使用了1
作为间隔值。但是,大多数浏览器中的最小值约为15
(请参阅 此处 了解更多信息。)浏览器将按照事件在执行队列中的顺序运行事件(在setInterval
中,事件尝试追赶。请参阅以下答案:马塞尔链接至,了解更多详细信息)。这意味着在第一个场景中,每 15 毫秒左右就会生成一个事件。因此计数器的递增速度更慢。但在第二种情况下,您有12 个事件,它们每隔 15 毫秒左右就会非常接近地触发,因此计数器的增量要快得多。
No, Javascript is single threaded. When you run
setInterval
orsetTimeout
, an event is generated which is then added to the browser's execution queue. So while you cannot guarantee that the code itself will run exactly when you want it to run, you can be sure that the event will be generated each time it is supposed to be generated. So in this case, you have 12 events that are being generated really close to each other. I notice that you've used1
as the interval value. However, the minimum values in most browsers is around15
(see here for more information.) The browser will run through the events in the order they are in the execution queue (insetInterval
, the events try to play catch up. Look at the answer that Marcel linked to, for more details).What this means is that in the first scenario you have one event generated every 15 or so milliseconds. So the counter is incremented more slowly. But in the second case, you have twelve events that are fired pretty close to each other every 15 or so milliseconds, and so the counter increments much faster.
在大多数浏览器中,JavaScript 计时器值至少设置为 15 毫秒,即使给出的值更小。据我所知,只有 Google Chrome 使用 4ms。另请参阅 的接受答案如何确定在 JavaScript 动画循环中使用的最佳“帧速率”(setInterval 延迟)? 。
JavaScript timer values are set to at least 15ms in most browsers, even if a smaller value is given. AFAIK only Google Chrome uses 4ms. See also the accepted answer of How to determine the best "framerate" (setInterval delay) to use in a JavaScript animation loop? .
不,JavaScript 没有多线程,至少目前还没有。
请阅读此答案了解
setInterval
的工作原理。No, JavaScript has no multithreading, at least not at the moment.
Please read this answer to see how
setInterval
works.您发布的代码无法运行,这里是更正后的代码:
如果您在代码运行时查看 CPU 性能,您会发现它几乎根本不起作用,这意味着较低的速率并不是由于代码被忙碌的。它根本不会按照您要求的频率触发间隔。
(如果您启动 12 个间隔,负载仍然几乎不明显。我启动了 200 个间隔,然后在其中一个核心上获得接近 100% 的负载。)
浏览器使用某种时钟来确定应该触发哪些间隔,并且时钟的分辨率通常低于毫秒。因此,直到下一个时钟滴答声才会再次触发该间隔,在您的情况下,间隔时间似乎约为 15 毫秒。
The code that you posted doesn't run, here is the corrected code:
If you look at the CPU performance while the code runs, you see that it's barely working at all, which means that the lower rate is not due to the code being busy. It simply won't fire the interval as often as you requested.
(If you start twelve intervals, the load is still barely noticable. I started 200 intervals before getting a load close to 100% on one of the cores.)
The browser uses some sort of clock to determine which intervals should be fired, and that clock usually has a lower resolution than milliseconds. So, the interval will not fire again until the next clock tick, which in your case seem to be about 15 ms apart.
传递给 setInterval 方法的第二个值确实是最小值。尽管 1 代表 1 毫秒,但大多数浏览器不太可能为您提供确切的超时时间。另一个答案说更有可能是 15 毫秒左右。
即便如此,第二项作为最小值足以解释第一个样本。
第二个样本也可以用这种行为来解释。您调用的每个
setInterval
方法都会注册一个完全独立的回调。它们各自的最小值为 1,但彼此不依赖。因此,所有这些都在相同的 1 毫秒间隔内触发是完全有效的(只要每个本身在重新触发之前等待 1 毫秒)。The second value passed to the
setInterval
method is indeed a minimum value. Although 1 represents 1 millisecond and it's unlikely that most browsers will give you exactly this timeout. Another answer says it's more likely to be around 15 milliseconds.Even so, the second item being a minimum value adequetely explains the first sample.
The second sample is also explained by this behavior. Each of the
setInterval
methods you calls registers a completely separate call back. They each have a minimum of 1 but no dependency on each other. So it's perfectly valid for all of them to fire within the same 1 millisecond interval (as long as each one itself waits 1 millisecond before re-firing).