【问题标题】:async/await understanding in node.jsnode.js 中的 async/await 理解
【发布时间】:2018-04-12 11:30:11
【问题描述】:

已经阅读了大量的文章和文档,但是这个主题对我来说仍然不够清楚。引用一个答案https://stackoverflow.com/a/46004461/630169

只要 async/await 中包含的代码是非阻塞的 它不会阻塞,例如,数据库调用、网络调用、文件系统调用。

但是如果包含在 async/await 中的代码是阻塞的,那么它会 阻塞整个 Node.js 进程,例如无限循环、CPU 图像处理等密集型任务。

但是,Understanding the node.js event loop 说:

当然,后端有DB的线程和进程 访问和进程执行。

在 C# 中,编写标记为 async 的函数并使用 await 调用就足够了,因此 .Net 将其放在另一个线程中。然而,它让我感到困惑的是,在 Node.js 中以不同方式组织的东西,async/await 函数仍然会阻塞主线程。

所以问题是:如何在 node.js 中编写(组织)任意async/await 函数以确保它将在单独的线程或进程中异步运行?有好的代码示例吗?一些npm 模块?让它没有比 C# 变体更棘手也很好。谢谢!

一些使其成为非阻塞的函数示例,例如,如果我想要同步 DB 调用来实现异步(非阻塞):

var Database = require('better-sqlite3');

var db = new Database('./my_db.sqlite');

async function DBRequest() {
    var row = db.prepare("SELECT * FROM table");
    return row;
};

注意: better-sqlite3 — 同步模块。

【问题讨论】:

  • “在 C# 中,编写标记为 async 的函数并使用 await 调用就足够了,因此 .Net 将其放在另一个线程中。”。这不是 async/await 的工作方式,这是您的基本误解 - 异步和线程是不同的概念,虽然 可能 使用 async/await 等待后台线程,但 不是 主要用例。
  • node.js 是单线程的。您可以编写长时间运行的阻塞代码,这样它就可以为其他函数产生执行时间——肯定有这样的技术——但阻塞代码就是阻塞代码。
  • @TKoL 需要很好的例子来制作阻塞代码 - 非阻塞。
  • 我不会给你一个具体的例子,但我可以向你解释如何去做。假设您要处理一个包含 100 个项目的数组,每个项目将花费 0.5 秒(阻塞时间)来处理——您想编写一个函数来处理它们,但您不希望它阻塞 50 秒。你要做的是编写你的函数来处理数组的一个元素,然后编写一个递归函数来在setTimeout 延迟后处理数组中的下一项。这是一种技术。
  • @TKoL 不适用于所有情况。需要更通用的方法。例如,我有同步 DB 库调用,并想创建使用它的函数async

标签: javascript c# node.js multithreading async-await


【解决方案1】:

这里有一些示例代码。决定提供它是一个值得的练习。

您可以编写长时间运行的阻塞代码,以便将执行时间留给其他函数

var array = new Array(100);
function processNext(){
    if (array.length === 0) return;
    var item = array.shift(); // gets first item from array and removes it.
    process(item); // 0.5 seconds of blocking time
    setTimeout(processNext ,500); // wait 0.5 seconds and then process the next one
    // during this waiting time, other code will run on your server.
}

processNext();

诚然,我是一个新手,由于我不知道的原因,这可能是一个非常糟糕的主意。

【讨论】:

  • 问题中添加的代码示例:如何将其转换为async(非阻塞)?
  • 大多数 sql 数据库交互几乎可以肯定已经是非阻塞的。我使用了一个 sql 节点库,它的大部分方法都返回了 Promise。
  • 您非常不清楚您到底想要什么。您似乎不了解什么是非阻塞,什么不是非阻塞,或者您需要它的情况。提供一些特定的阻塞代码,我可以潜在地向您展示如何使用上述技术使其片段一次运行,但在片段之间让步给代码的其他部分.
  • 问题已编辑,示例在那里,提到的库被阻止。
  • 抱歉,您是说单行代码db.prepare("SELECT * FROM table"); 阻塞了?如果这就是你所说的那么......它几乎肯定不会阻塞足够长的时间来担心,如果是这样,除了可能创建超时条件之外你无能为力。
【解决方案2】:

您真的受制于您在此处使用的库 - 如果代码是同步的且不受 I/O 限制,那么您实际上无法在 Node 进程中执行太多其他操作来使其异步。

您唯一真正的选择是将代码移到它自己的进程中,从而使其受 I/O 限制,这样您的应用程序可以等待它而不阻塞它自己的线程。

【讨论】:

  • 该库只是示例。只是询问一种使任何功能async 和非阻塞的方法。似乎在 JS 中 async/await 什么都不做。它只是简化了 Promise 的使用。如果底层函数没有promise,那么你就不能让它async和非阻塞。
  • @AlekseyKontsevich 您的问题在 Node 上是不可能实现的 - 在您的 Node 进程中执行的任何代码都会在某个时候占用线程。如果您调用的代码是阻塞的,那么最终它将阻塞线程直到它完成。 Node 与多线程环境(如您提到的 C#)的不同之处在于它们可以生成新线程并卸载工作,Node 不能这样做,因为它是故意单线程的,以避免线程管理的复杂性。如果你觉得你需要线程,那么你可能使用了错误的工具来完成这项工作....
  • @AlekseyKontsevich 它不会“什么都不做”,它与 C# 中的 async/await 执行相同的操作,这允许您使用类似同步的构造来表示异步进程。它不允许您在任何一种语言中“使阻塞代码成为非阻塞”,因为这没有意义。
  • @AntP IIRC C# async/await 的不同之处在于它可以将同步代码卸载到工作线程(至少 await 关键字可以),而对于 Node,它只是有效的语法糖。你的观点仍然存在,我试图再次强调同一点,没有神奇的代码可以将阻塞代码变成非阻塞......
【解决方案3】:

我的兴趣不是没有的——在我之前people asked 以及on stackoverflow(和here)的类似问题:

但时间长、受 CPU 限制的任务是什么?

当任务在手时,如何避免阻塞事件循环 不受 I/O 限制,并且持续时间超过几分之一毫秒? 你根本不能,因为没有办法......好吧,没有 在threads_a_gogo之前。

为了解决这些问题,他们已经创建了一堆模块,其中一些模块,例如 threads,在浏览器和 Node.js 中都可以工作:

如果有人可以将async/await 附加到他们或提供很好的例子,那就太好了。

顺便说一句,here's a comrade tests 在 Threads à gogo 上驱动 - 使用线程的结果是 40x faster,而不是使用 Cluster。所以 Node.js 的单线程想法并不总是很好。

【讨论】:

  • 不知道你的回答补充了什么,这个线程中的每个人都没有指出......
  • 几乎可以再次归结为,如果您正在尝试构建一个严重依赖多线程的应用程序,Node 可能不是正确的工具。
猜你喜欢
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
  • 2020-03-25
  • 2018-10-13
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
  • 2018-04-13
相关资源
最近更新 更多