Nodejs - неблокирующий обратный вызов события libuv

Я пытаюсь создать приложение с использованием Node.Js, для которого требуется поддержка собственного модуля. Я использовал библиотеку libuv через приложение, и мне удалось заставить работать большинство асинхронных методов, за исключением той части, где мне пришлось реализовать обратный вызов события прогресса. Я хочу реализовать обратный вызов события прогресса асинхронно и без блокировки цикла событий Node.js.

Вот фрагменты кода:

native.cc

#include <node.h>
#include <uv.h>
#include "nbind/nbind.h"    

using v8::Isolate;
using v8::HandleScope;


int FileProgressCallback(uint64_t const sent, uint64_t const total, void const *const data) {
    nbind::cbFunction cb = *((nbind::cbFunction *) data);
    cb(sent, total);
    return 0;
}

class WorkerFileTransfer {
public:
    WorkerFileTransfer(std::string path, nbind::cbFunction cb) :
            callback(cb), path(path) {};

    uv_work_t worker;
    nbind::cbFunction callback;

    bool error;
    std::string errorMsg;

    std::string path;
};

void FileTransferDone(uv_work_t *order, int status) {
    Isolate *isolate = Isolate::GetCurrent();
    HandleScope handleScope(isolate);

    WorkerFileTransfer *work = static_cast< WorkerFileTransfer * >( order->data );

    if (work->error) {
        work->callback.call<void>(work->errorMsg.c_str(), work->output);
    } else {
        ThirdPartyLibraryFileCopy(work->path.c_str(), FileProgressCallback, (const void *) &work->callback);
    }

    // Memory cleanup
    work->callback.reset();
    delete work;
}

void FileTransferRunner(uv_work_t *order) {
    WorkerFileTransfer *work = static_cast< WorkerFileTransfer * >( order->data );

    try {
        work->output = true;
    }
    catch (...) {
        work->error = true;
        work->errorMsg = "Error occured while executing the method...";
    }
}

void FileTransfer(const std::string path, nbind::cbFunction &callback) {
    WorkerFileTransfer *work = new WorkerFileTransfer(path, callback);

    work->worker.data = work;
    work->path = path;
    work->error = false;

    uv_queue_work(uv_default_loop(), &work->worker, FileTransferRunner, FileTransferDone);
}

function(FileTransfer);

test.js

FileTransfer(
  '/path/file.txt',
  (sent, total) => {

    console.log(`sent`, sent);
    console.log('total', total);
  }
);

Мне удалось добиться передачи файла из-за приведенных ниже строк, но здесь блокируется цикл событий Node.Js.

void FileTransferDone(uv_work_t *order, int status) {
   ...

   ThirdPartyLibraryFileCopy(work->path.c_str(), FileProgressCallback, (const void *) &work->callback);

   ...
}

Когда я перемещаю строку ThirdPartyLibraryFileCopy(work->path.c_str(), FileProgressCallback, (const void *) &work->callback); в метод FileTransferRunner(uv_work_t *order), я не получаю никакого вывода в функции обратного вызова javascript.

Как получить значения прогресса в функции обратного вызова javascript асинхронно, не блокируя цикл событий Node.Js?


person Ganesh Rathinavel    schedule 28.05.2019    source источник
comment
если вы пропустили ответ @saghul, это поможет?   -  person Can Rau    schedule 20.10.2019
comment
@Can Я рад слышать, что вы хотели бы использовать мое приложение. Я не смог решить эту проблему из-за своих ограниченных знаний в C++. Если кто-то заинтересован в исправлении этой ошибки, пожалуйста, давайте его выложим. github.com/ganeshrvel/openmtp/issues/8   -  person Ganesh Rathinavel    schedule 21.10.2019


Ответы (1)


Согласно документации uv_queue_work: http://docs.libuv.org/en/v1.x/threadpool.html#c.uv_queue_work Обратный вызов work (FileTransferRunner в вашем случае) выполняется в пуле потоков, но обратный вызов done (FileTransferDone в вашем случае) выполняется в потоке цикла. Таким образом, если вы выполните операцию блокировки на последнем, вы заблокируете цикл.

Если вы хотите периодически отправлять отчеты о проделанной работе, эта модель вам не подойдет. Вы можете использовать асинхронный дескриптор uv_async_t и сообщать о прогрессе, используя uv_async_send (который является потокобезопасным) из рабочей функции. Или используйте несколько рабочих запросов для отправки фрагментов (это, вероятно, будет медленнее).

person saghul    schedule 15.10.2019