非常快速的无穷循环,不会阻塞I / O [英] Very fast endless loop without blocking I/O

查看:74
本文介绍了非常快速的无穷循环,不会阻塞I / O的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于不阻塞I / O的无限循环,是否有比 window.requestAnimationFrame()更快的替代方法?

Is there a faster alternative to window.requestAnimationFrame() for endless loops that don't block I/O?

我在循环中所做的与动画无关,所以我不在乎下一帧何时准备就绪,而且我已经读过 window.requestAnimationFrame()受监视器刷新率的限制,或者至少等到可以绘制一帧。

What I'm doing in the loop isn't related to animation so I don't care when the next frame is ready, and I have read that window.requestAnimationFrame() is capped by the monitor's refresh rate or at least waits until a frame can be drawn.

我也尝试了以下方法:

function myLoop() {
    // stuff in loop
    setTimeout(myLoop, 4);
}

(之四是因为这是 setTimeout ,较小的值仍将默认为4。)但是,我需要比这更好的分辨率。

(The 4 is because that is the minimum interval in setTimeout and smaller values will still default to 4.) However, I need better resolution than this.

是否有任何性能更好的东西?

Is there anything with even better performance out there?

我基本上需要一个非阻塞版本的 while(true)

I basically need a non-blocking version of while(true).

推荐答案

两件事比 setTimeout 运行得早:

  • process.nextTick callbacks (NodeJS-specific):


process.nextTick()方法将回调添加到下一个滴答队列中。一旦当前循环的事件循环运行完毕,将调用当前下一个刻度队列中的所有回调。

The process.nextTick() method adds the callback to the "next tick queue". Once the current turn of the event loop turn runs to completion, all callbacks currently in the next tick queue will be called.

这不是<$ c的简单别名$ c> setTimeout(fn,0)。它效率更高。它会在事件循环的后续滴答声中触发任何其他I / O事件(包括计时器)之前。

This is not a simple alias to setTimeout(fn, 0). It is much more efficient. It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.


  • 承诺清算通知

  • Promise settlement notifications

    因此,这些可能是您的工具带的工具,将具有 setTimeout 来实现所需的余额。

    So those might be a tools for your toolbelt, doing a mix of one or both of those with setTimeout to achieve the balance you want.

    详细信息:

    您可能已经知道,给定的JavaScript线程基于任务队列运行(规范将其称为作业队列);并且您可能知道,浏览器中有一个主要的默认UI线程,NodeJS运行一个线程。

    As you probably know, a given JavaScript thread runs on the basis of a task queue (the spec calls it a job queue); and as you probably know, there's one main default UI thread in browsers and NodeJS runs a single thread.

    但实际上,现代实现中至少有两个任务队列:我们都想到的主要对象( setTimeout 和事件处理程序放置任务的位置),以及 microtask队列,在处理主对象期间放置某些异步操作任务(或宏任务)。宏任务完成后,即在主队列中的下一个宏任务之前 ,将立即处理这些微任务。即使下一个宏任务在微任务之前就已排队。

    But in fact, there are at least two task queues in modern implementations: The main one we all think of (where setTimeout and event handlers put their tasks), and the "microtask" queue where certain async operations are placed during the processing of a main task (or "macrotask"). Those microtasks are processed as soon as the macrotask completes, before the next macrotask in the main queue — even if that next macrotask was queued before the microtasks were.

    nextTick 回调和承诺结算通知都是微任务。因此,调度既可以调度异步回调,也可以调度异步回调,但是该回调将在下一个主要任务之前发生。

    nextTick callbacks and promise settlement notifications are both microtasks. So scheduling either schedules an async callback, but one which will happen before the next main task.

    我们可以在浏览器中使用 setInterval 和一个承诺解决链:

    We can see that in the browser with setInterval and a promise resolution chain:

    let counter = 0;
    
    // setInterval schedules macrotasks
    let timer = setInterval(() => {
      $("#ticker").text(++counter);
    }, 100);
    
    // Interrupt it
    $("#hog").on("click", function() {
      let x = 300000;
    
      // Queue a single microtask at the start
      Promise.resolve().then(() => console.log(Date.now(), "Begin"));
    
      // `next` schedules a 300k microtasks (promise settlement
      // notifications), which jump ahead of the next task in the main
      // task queue; then we add one at the end to say we're done
      next().then(() => console.log(Date.now(), "End"));
    
      function next() {
        if (--x > 0) {
          if (x === 150000) {
            // In the middle; queue one in the middle
            Promise.resolve().then(function() {
              console.log(Date.now(), "Middle");
            });
          }
          return Promise.resolve().then(next);
        } else {
          return 0;
        }
      }
    });
    
    $("#stop").on("click", function() {
      clearInterval(timer);
    });

    <div id="ticker">&nbsp;</div>
    <div><input id="stop" type="button" value="Stop"></div>
    <div><input id="hog" type="button" value="Hog"></div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    运行该命令并单击 Hog 按钮时,请注意计数器的显示如何冻结,然后继续运行。这是因为提前安排了300,000个微任务。还要注意我们编写的三个日志消息上的时间戳(直到宏任务显示它们时它们才会出现在代码片段控制台中,但是时间戳会在它们记录时向我们显示)。

    When you run that and click the Hog button, note how the counter display freezes, then keeps going again. That's because of the 300,000 microtasks that get scheduled ahead of it. Also note the timestamps on the three log messages we write (they don't appear in the snippet console until a macrotask displays them, but the timestamps show us when they were logged).

    因此,基本上,您可以安排一堆微任务,并定期让它们用完并运行下一个宏任务。

    So basically, you could schedule a bunch of microtasks, and periodically let those run out and run the next macrotask.

    注意:我已使用 setInterval 作为代码段中的浏览器示例,但使用了 setInterval 特别地,对于使用NodeJS进行的类似实验而言,它可能不是一个好选择,因为NodeJS的 setInterval 与浏览器中的有点不同,并且具有一些令人惊讶的计时特性。

    Note: I've used setInterval for the browser example in the snippet, but setInterval, specifically, may not be a good choice for a similar experiment using NodeJS, as NodeJS's setInterval is a bit different from the one in browsers and has some surprising timing characteristics.

    这篇关于非常快速的无穷循环,不会阻塞I / O的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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