Nodejs 同步,异步问题

Nodejs 同步,异步问题

node.js 的c++ 扩展部份代码是异步执行的么?如果不是,如何创建自定义的异步代码。 比如,用户可选择该部份代码是同步执行,还是异步。

8 回复

Node.js 同步与异步问题

在 Node.js 中,处理 I/O 操作时通常使用异步编程模型。这是因为 Node.js 采用单线程事件循环机制来处理并发操作,以提高性能和响应性。然而,在某些情况下,如处理 C++ 扩展模块时,你可能需要考虑同步或异步执行。

Node.js 中的同步 vs 异步

同步:同步代码会阻塞后续代码的执行,直到当前操作完成。这种方式简单直接,但可能导致程序响应变慢,特别是在执行耗时操作时。

异步:异步代码不会阻塞执行流程,而是通过回调函数、Promise 或 async/await 来处理结果。这种方式可以让 Node.js 更高效地处理多个任务。

示例:Node.js 中的同步与异步

假设我们有一个简单的文件读取操作:

// 同步方式
const fs = require('fs');

try {
    const data = fs.readFileSync('./example.txt', 'utf8');
    console.log(data);
} catch (err) {
    console.error(err);
}

在上面的例子中,readFileSync 是一个同步方法,它会阻塞后续代码的执行直到文件读取完成。

现在来看异步版本:

// 异步方式
const fs = require('fs');

fs.readFile('./example.txt', 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});

在这个例子中,readFile 是一个异步方法,它通过回调函数来处理结果,不会阻塞后续代码的执行。

如何创建自定义异步代码

如果你想创建自定义的异步代码,可以使用 async 函数和 Promise。例如:

function readFileAsync(filePath) {
    return new Promise((resolve, reject) => {
        fs.readFile(filePath, 'utf8', (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

// 使用 async/await
async function processFile() {
    try {
        const data = await readFileAsync('./example.txt');
        console.log(data);
    } catch (err) {
        console.error(err);
    }
}

processFile();

在这个例子中,我们定义了一个返回 PromisereadFileAsync 函数,并使用 async/await 来处理异步操作。

结论

在 Node.js 中,选择同步还是异步取决于你的具体需求。对于 I/O 操作,通常推荐使用异步方式来避免阻塞事件循环。对于 C++ 扩展模块,你可以根据需要选择同步或异步执行方式。希望这些示例能帮助你更好地理解和应用 Node.js 中的同步与异步编程。


可异步可同步。google关键词node.js extension c++就能找不到不少介绍 https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/ 这篇是我看过的不错的入门介绍,里面有一段Hello World with Asynchronous IO,应该是楼主要找的。

这篇比较早了,2010年的,现在node使用libuv作为跨平台的异步库了,github和api地址在这里,楼主可以去看看 https://github.com/joyent/libuv

我的理解:异步I/O就是靠epoll/kqueue(*nix)或IOCP(windows),本质是系统内核级别的线程池,异步计算也是要靠多线程,libuv内部就有一个线程池,你可以将任务扔给这些线程去做,总之异步是离不了多线程的,而node.js的所谓单线程仅指执行javascript的线程,底层还有其它线程的配合。不知道对不对?

底层应该没有其它线程配合吧,它本身是事件驱动和单进程的上下文,并发的越多,事件注册的越多,当并发到一定数量nodejs就会挂,说明单进程满了,没法再注册回调事件了;当然,一般的小应用不会有什么问题的,大的话我计划做nodejs链,还没想好,大的思路是做多个node服务器串起来,不知行不行~

底层应该是有多线程的,你可以去看下libuv的源码。。。 小应用到大应用就是伸缩性的问题:垂直伸缩或水平伸缩,多个node服务器串起来指的是业务分层吗?个人感觉node.js一般用来做I/O密集应用,这种情况一般是水平伸缩,也就是分布式。

对,除了javascript 代码,其它的都是多线程在做。

Node.js 中的 C++ 扩展可以实现为同步或异步操作。默认情况下,C++ 扩展函数是同步的。如果你想创建一个异步操作,你需要使用 Node.js 的异步 API 或者将任务放到工作线程中执行。

示例代码

1. 创建一个同步的 C++ 扩展

假设我们有一个简单的 C++ 扩展函数,它会执行一个耗时操作(例如计算),并且是同步的:

// myaddon.cc
#include <node_api.h>

napi_value MySyncFunction(napi_env env, napi_callback_info info) {
  size_t argc = 1;
  napi_value argv[1];
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));

  // 这里模拟一个耗时操作
  for (int i = 0; i < 1000000000; ++i) {}

  return nullptr;
}

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_value fn;

  status = napi_create_function(env, nullptr, 0, MySyncFunction, nullptr, &fn);
  if (status != napi_ok) return nullptr;

  return fn;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

编译并加载此扩展后,你可以调用 MySyncFunction,这将阻塞当前线程直到完成。

2. 创建一个异步的 C++ 扩展

如果你希望你的 C++ 扩展能够异步执行,你可以使用 Node.js 的异步回调机制:

// myaddon_async.cc
#include <node_api.h>

napi_value MyAsyncFunction(napi_env env, napi_callback_info info) {
  napi_status status;

  napi_value promise;
  status = napi_create_promise(env, &deferred, &promise);
  if (status != napi_ok) return nullptr;

  // 异步执行任务
  std::thread task([=]() {
    for (int i = 0; i < 1000000000; ++i) {}

    // 完成后调用 JavaScript 回调
    napi_handle_scope scope;
    napi_open_handle_scope(env, &scope);

    napi_value result;
    napi_create_int32(env, 42, &result);

    napi_resolve_deferred(env, deferred, result);

    napi_close_handle_scope(env, scope);
  });

  task.detach();

  return promise;
}

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_value fn;

  status = napi_create_function(env, nullptr, 0, MyAsyncFunction, nullptr, &fn);
  if (status != napi_ok) return nullptr;

  return fn;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

在这个例子中,MyAsyncFunction 创建了一个异步线程来执行耗时操作,并使用 napi_deferrednapi_resolve_deferred 来处理结果。

通过这种方式,你可以让用户选择扩展部分代码是同步执行还是异步执行。

回到顶部