nodejs建立線程問題

咱們知道在nodejs中可使用new Worker建立線程。今天有個同窗剛好問到,怎麼判斷建立線程成功,這也是最近開發線程池的時候遇到的問題。nodejs文檔裏也沒有提到如何捕獲建立失敗這種狀況。因此只能經過源碼去找答案。不過壞消息是,咱們沒法捕獲這個這個錯誤。下面看一下源碼。咱們直接從c++層開始分析。
   當咱們調用new Worker的時候,最後會調用c++的StartThread函數(node_worker.cc)建立一個線程。node

CHECK_EQ(uv_thread_create_ex(&w->tid_, &thread_options, [](void* arg) {
    // ...
  }, static_cast<void*>(w)), 0);

咱們看uv_thread_create_ex的邏輯linux

int uv_thread_create_ex(uv_thread_t* tid,
                        const uv_thread_options_t* params,
                        void (*entry)
(void *arg),
                        void *arg) 
{
  // 忽略部分代碼
  err = pthread_create(tid, attr, f.out, arg);
  return UV__ERR(err);
}

接着咱們看一下pthread_create的返回值定義c++

On success, pthread_create() returns 0; on error, it returns an error
      number, and the contents of *thread are undefined.web

因此,若是uv_thread_create_ex返回非0,即pthread_create返回非0。表示報錯。咱們回頭看一下返回非0時,c++的處理。咱們對c++層的CHECK_EQ(uv_thread_create_ex(…), 0)進行宏展開。編程

#define CHECK_EQ(a, b) CHECK((a) == (b))

#define CHECK(expr)                                                           \
  do {                                                                        \
    if (UNLIKELY(!(expr))) {                                                  \
      ERROR_AND_ABORT(expr);                                                  \
    }                                                                         \
  } while (0)


#define UNLIKELY(expr) expr

經過一些列展開,最後變成微信

  do {                                                                        
    if (!(返回值 == 0)) {                                                  
      ERROR_AND_ABORT(expr);                                                  
    }                                                                         
  } while (0)

由於建立線程時返回非0,因此這裏是true。咱們繼續看ERROR_AND_ABORT多線程

#define ERROR_AND_ABORT(expr)                                                 \
  do {                                                                

    static const node::AssertionInfo args = {                                 \
      __FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME           \
    };                                                                        \
    node::Assert(args);                                                       \
  } while (0)

拼接錯誤信息,而後執行node::Assert(args);less

[[noreturn]] void Assert(const AssertionInfo& info) {
  char name[1024];
  GetHumanReadableProcessName(&name);

  fprintf(stderr,
          "%s: %s:%s%s Assertion `%s' failed.\n",
          name,
          info.file_line,
          info.function,
          *info.function ? ":" : "",
          info.message);
  fflush(stderr);

  Abort();
}

重點是Abort,函數

[[noreturn]] void Abort() {
  DumpBacktrace(stderr);
  fflush(stderr);
  ABORT_NO_BACKTRACE();
}

繼續看ABORT_NO_BACKTRACE測試

#ifdef _WIN32
#define ABORT_NO_BACKTRACE() _exit(134)
#else
#define ABORT_NO_BACKTRACE() abort()
#endif

因此最終調用的是_exit或abort退出或者終止進程。咱們討論linux下的狀況。咱們看abort函數的說明

The abort() function first unblocks the SIGABRT signal, and then
      raises that signal for the calling process (as though raise(3) was
      called).  This results in the abnormal termination of the process
      unless the SIGABRT signal is caught and the signal handler does not
      return (see longjmp(3)).
      If the SIGABRT signal is ignored, or caught by a handler that
      returns, the abort() function will still terminate the process.  It
      does this by restoring the default disposition for SIGABRT and then
      raising the signal for a second time.

abort函數會給進程發送SIGABRT信號,咱們能夠註冊函數處理這個信號,不過咱們仍是沒法阻止進程的退出,由於他執行完咱們的處理函數後,會把處理函數註冊爲系統的默認的,而後再次發送SIGABRT信號,而默認的行爲就是終止進程。咱們來個測試。

const { Worker, threadId } = require('worker_threads');
for (let i = 0; i < 1000; i++) {
    const worker = new Worker('var a = 1;', { eval: true });
}

咱們建立1000個線程。結果


總結:在nodejs建立過多的線程可能會致使進程終止。而咱們沒法阻止這個行爲。因此在nodejs裏使用多線程的時候,咱們須要注意的就是不要開啓過多的線程,而在建立線程的時候,咱們也不須要關注是否成功,由於只要進程不掛掉,那就是成功。對於業務錯誤咱們能夠註冊error事件處理,在new Worker的時候,咱們能夠加try catch。能夠捕獲一下參數錯誤的狀況。

本文分享自微信公衆號 - 編程雜技(theanarkh)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索