Дополнение N-API C , вызывающее блокировку Electron GUI

#javascript #c #electron #node.js-addon #n-api

#javascript #c #electron #node.js-дополнение #n-api

Вопрос:

У меня есть дополнение N-API C , которое я хотел бы использовать с Electron GUI. В настоящее время дополнение C имеет простую функцию, которая отключается на 10 секунд, а затем выполняет вычисление 8 * 2 и возвращает значение в код Javascript. Код Javascript запускает дополнение C каждые 10 секунд.

 // index.js
const addon = require('./build/Release/module');
const electron = require('electron');
const {app, BrowserWindow} = require('electron');
let win;

function createWindow() {
  win = new BrowserWindow({width: 800, height: 600});
  win.loadFile('./index.html');
  win.on('closed', () => {win = null});
}

app.on('ready', createWindow);

app.on('activate', () => {
  if (win === null) {
    createWindow();
  }
})


function getInfoFromNativeModule() {
  const value = 8;
  console.log(`${value} times 2 equals`, addon.my_function(value));
  setTimeout(getInfoFromNativeModule, 1000);
}

getInfoFromNativeModule();
  

Однако, когда я запускаю приведенный выше код, я обнаруживаю, что собственный аддон C вызывает блокировку Electron GUI на 10 секунд при каждом запуске. Есть ли какой-либо способ, которым я могу выполнить свои тяжелые вычисления в фоновом режиме и при этом Electron GUI не блокируется и не зависает? Я предполагаю, что мне пришлось бы использовать какие-то потоки, но я не уверен, как это сделать с помощью N-API. Ниже приведены остальные мои файлы, включая module.cpp и файл package.json.

 // module.cpp
napi_value MyFunction(napi_env env, napi_callback_info info) {
  napi_status status;
  size_t argc = 1;
  int number = 0;
  napi_value argv[1];
  status = napi_get_cb_info(env, info, amp;argc, argv, NULL, NULL);

  if (status != napi_ok) {
    napi_throw_error(env, NULL, "Failed to parse arguments");
  }

  status = napi_get_value_int32(env, argv[0], amp;number);

  if (status != napi_ok) {
    napi_throw_error(env, NULL, "Invalid number was passed as argument");
  }
  napi_value myNumber;
  number = number * 2;
  std::cout << "sleeping for 10 seconds" << std::endl;
  sleep(10);
  std::cout << "waking up" << std::endl;
  status = napi_create_int32(env, number, amp;myNumber);

  if (status != napi_ok) {
    napi_throw_error(env, NULL, "Unable to create return value");
  }

  return myNumber;
}

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

  status = napi_create_function(env, NULL, 0, MyFunction, NULL, amp;fn);
  if (status != napi_ok) {
    napi_throw_error(env, NULL, "Unable to wrap native function");
  }

  status = napi_set_named_property(env, exports, "my_function", fn);
  if (status != napi_ok) {
    napi_throw_error(env, NULL, "Unable to populate exports");
  }

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)



// package.json
{
  "name": "n-api-article",
  "version": "0.1.0",
  "main": "index.js",
  "scripts": {
    "start": "node-gyp rebuild amp;amp; electron .",
    "test": "echo "Error: no test specified" amp;amp; exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git https://github.com/schahriar/n-api-article.git"
  },
  "engines": {
    "node": ">=8.4.0"
  },
  "dependencies": {
    "electron": "^4.0.8",
    "electron-rebuild": "^1.8.4"
  }
}
  

Ответ №1:

Причина, по которой он блокирует Электрон , заключается в sleep(10) . Этот вызов не отвечает в течение 10 секунд.

Так что да, есть способ перенести тяжелые вычисления в другой поток. Самая большая сложность при этом заключается в том, что поток не может выполнить обратный вызов JavaScript без принятия дополнительных мер предосторожности и не может получить доступ к структурам данных JavaScript, поэтому ему должны быть предоставлены все необходимые данные.

Вот пример, который абстракция C предоставляет для N-API, использующего поток для вычисления Pi.

узел-дополнение-пример

И вот C -оболочки для создания потокобезопасных обратных вызовов.

napi-threadsafe-обратный вызов

Это не тривиально, но эти два примера должны помочь вам справиться с этим.