什么都没等?使用空等待来破坏大型同步功能 [英] Await nothing? Using an empty await to break up a large synchronous function

查看:56
本文介绍了什么都没等?使用空等待来破坏大型同步功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很简单的问题,找不到答案.

I have a rather simple question that I can't find an answer to.

我有一个名为 foo 的异步函数,该函数永远不会等待,因此它是同步运行的.在 foo 中是一个长时间运行的循环,它将大量数据推入中间缓冲区.有一个使用RxJS的异步操作,它将从该缓冲区中提取并处理数据,但是直到我长时间运行的循环以某种方式产生,或者当该循环完全完成时,它才会执行,将数百万个数据点推入中间缓冲区中(不好)).

I have an async function called foo that never awaits, so it's run synchronously. In foo is a long-running loop and it pushes a lot of data into a intermediary buffer. There is an async operation using RxJS that will pull and process data from that buffer, but it won't execute until my long running loop yields somehow, or when the loop is completely done pushing millions of data points into the intermediary buffer (not good).

我可以等待未定义的还是一个虚拟值,以使 foo 可以屈服于正在等待的事件?还是promise会立即返回,因为它会立即被伪值解析并且函数将不会产生结果?

Can I await undefined or a dummy value, so that foo can yield to events that are waiting? Or will the promise return immediately because it's immediately resolved with a dummy value, and the function won't yield?

推荐答案

如果您有一段长时间运行的同步代码想要对其他事物产生更多的收益,则可以在节点中采用多种方法进行处理.js,每种都有各自的优点/缺点:

If you have a section of long running synchronous code that you want to yield more to other things, there are a number of ways to go about that in node.js, each with their own advantages/disadvantages:

  1. 将长时间运行的同步代码移动到另一个node.js进程,并将完成情况传达回主进程.如果您确实希望长时间运行的同步代码完全不干扰node.js代码的其余工作,那么这是最清晰的方法.如果您定期运行此代码或从多个请求运行它,甚至可以创建工作队列和多个其他进程来运行任务.那些进行诸如图像识别或其他复杂数据分析之类的耗时工作的人们都希望将这种耗时的代码完全从主要的node.js事件循环中移除.

  1. Move the long running synchronous code to another node.js process and communicate completion back to the main process. If you truly want your long running synchronous code to not interfere at all with the rest of what your node.js code is doing, this is the clearest way to do that. If you run this code regularly or run it from multiple requests, you can even create a work queue and multiple other processes to run the tasks. People that do time consuming things like image recognition or other complicated data analysis, all want to get that time consuming code out of the main node.js event loop entirely.

使用node.js中的新Workers将此长时间运行的同步代码移出主循环.这将带来一些局限性,因为工作人员必须独自站立(有点像浏览器中的webWorkers)并通过消息传递与主线程进行通信.

Use the new Workers in node.js to move this long running synchronous code out of the main loop. This will come with some limitations since workers have to pretty much stand on their own (kind of like webWorkers in a browser) and communicate with the main thread with messaging.

将您的同步代码分解为小的工作单元,并在计时器刻度上执行每个单元.这样一来,事件循环就可以在您的工作单元之间运行其他任务.通常,这是大量的工作,需要重写代码,因为您本质上必须创建某种状态机,并且必须将处理分解为足够小的工作单元以执行工作单元,并将状态完全保存为某种类型对象,退出,让node.js做其他事情,然后在某种计时器上调用它来执行另一个工作单元.您也可以以某种方式使用promises/await,但是promises的优先级更高,因此您可能仍会在node.js代码中饿死其他一些操作.工作单元也可以在对生成器的调用中执行,状态可以保存在生成​​器函数中.

Break your synchronous code into small units of work and execute each unit on a timer tick. That allows the event loop to run other tasks between your units of work. This is typically a significant amount of work rewriting the code because you essentially have to create some sort of state machine and you have to break your processing into small enough work units that you can execute a work unit, have the state fully saved into some type of object, exit out, let node.js do some other things, then on some sort of timer get called to execute another work unit. You can also use promises/await for this in some fashion, but promises have a somewhat higher priority so you may still be starving some other operations in your node.js code. A unit of work could also be executed on a call to a generator, where state could be saved in your generator function.

在大多数情况下,如果您选择选项#1或#2,则代码重写量最少,尽管您对实际代码的实际作用并没有太多分享,但我们可以自己在这方面提出意见.而且,只有#1和#2才能真正从主要的node.js线程中获得长时间运行的CPU工作.选项#3,无论是使用计时器还是使用Promise,都只能与其他任务进行更多的交织,但是CPU仍然经常因同步工作而陷入困境.

In most cases, there's the least amount of code rewriting if you pick option #1 or #2 though you don't really share much about what the actual code is doing for us to offer an opinion on that front ourselves. And, only #1 and #2 really get the long running CPU work out of the main node.js thread. Options #3, whether done with timers or promises, only allows for more interleaving with other tasks, but the CPU is still regularly bogged down with your synchronous work.

我可以等待未定义的值或伪值,以便foo可以屈服于正在等待的事件吗?

Can I await undefined or a dummy value, so that foo can yield to events that are waiting?

排序.Promise .then()处理程序以比事件循环中所有事件更高的优先级运行,因此使用 await 产生将允许事件循环中的其他一些事情运行(例如其他待处理的 .then()处理程序),但不允许其他所有内容运行(例如待处理的计时器).因此,我真的不建议在某个常量上插入 await 作为解决事件循环中所有事件之间公平"调度的解决方案,因为它无法实现这一目标.它将使某些(但不是全部)其他事物与您的工作交织在一起.

Sort of. Promise .then() handlers run at a bit higher priority than all events in the event loop so using an await to yield will allow some other things in the event loop to run (like other pending .then() handlers) but won't allow all other things to run (like pending timers). So, I wouldn't really recommend inserting an await on some constant as a solution for "fair" scheduling among all things in the event loop as it won't achieve that. It will allow some (but not all) other things to interleave with your work.

仅供参考,您可以通过等待来允许其他计时器运行,例如在本示例中等待一个计时器,但是您还必须在事件循环中测试所有其他类型的事情(网络,磁盘I/O,等等...)查看是否允许他们运行:

FYI, you can allow other timers to run by making your await, await a timer such as in this example, but you'd have to also test all the other types of things in the event loop (networking, disk I/O, etc...) to see if it allowed them to run:

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }

    let start = Date.now();

    // long running function
    async function run() {
        let i = 0;
        let y;
        while(i++ < 1000000000) {
            for (let t = 0; t < 100; t++) {
                let x = 20;
                y = Math.pow(x,i);
            }
            await delay(1);
        }
        return i;
    }
    
    run();

    setInterval(() => {
        let delta = Date.now() - start;
        console.log((delta/1000).toFixed(3));
    }, 50);

我的建议仍然是上面的选项1或#2,以使另一个线程/进程参与您的长时间运行操作,因为这对于node.js总是更好.

My recommendation is still option #1 or #2 above to get another thread/process involved for your long running operation as that's always better for node.js.

这篇关于什么都没等?使用空等待来破坏大型同步功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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