标签: libuv

libuv与Boost/ASIO相比如何?

我会对以下方面感兴趣:

  • 范围/功能
  • 性能
  • 到期

c++ boost boost-asio libuv

221
推荐指数
3
解决办法
5万
查看次数

异步javascript如何在Node.js中解释和执行?

我最近一直在研究Node.js的核心,我对Node平台的内部工作有一些疑问.据我了解,Node.js的工作原理如下:

在此输入图像描述

Node有一个用Javascript编写的API,它允许程序员与文件系统和网络之类的东西进行交互.但是,所有这些功能实际上都是由C/C++代码完成的,也是Node的一部分.事情变得模糊不清.因此,Chrome V8引擎的工作基本上是"编译"(解释?)javascript到机器代码.V8是用C++编写的,而Javascript语言本身是由ECMA指定的,因此关键字和语言特征等都是由它们定义的.这引出了我的前几个问题:

  1. Node Node Library如何与Node Bindings交互,因为Node Bindings是用C++编写的?

  2. Chrome V8引擎如何在Node的上下文中解释Javascript?我知道它使用了一种名为JIT的技术,在类似的问题中提到过:(https://softwareengineering.stackexchange.com/questions/291230/how-does-chrome-v8-work-and-why-was-javascript- not-jit-first-first-first-pl)但这并没有解释如何在Node的上下文中解释Javascript.与Node一起提供的Chrome V8引擎与Chrome浏览器上运行的引擎完全相同,还是已经过修改以与Node配合使用?

这让我想到了下一个问题.因此Node具有事件驱动的非阻塞IO.它通过事件循环实现了这一点,虽然它通常被称为"节点事件循环",但它实际上是libuv库的一部分,libuv库是一个旨在提供异步IO的C++库.在较高的层次上,事件循环基本上是通过Callbacks访问的,Callbacks是一个原生的Javascript功能,也是选择Javascript作为Node项目语言的原因之一.下面是事件循环如何工作的说明:

在此输入图像描述

这也可以通过这个简洁的小网站现场演示:http://latentflip.com/loupe/ 假设我们的Node应用程序需要调用外部API.所以我们写这个:

request(..., function eyeOfTheTiger() {
   console.log("Rising up to the challenge of our rival");
});
Run Code Online (Sandbox Code Playgroud)

我们的调用request被推送到调用堆栈,我们的回调被传递到某处,在那里它被保留直到请求操作完成.如果是,则将回调传递到回调队列.每次清除调用堆栈时,事件循环都会将回调队列顶部的项目推送到调用堆栈,然后执行该调用.此事件循环在单个线程上运行.出现问题的地方是有人写"阻塞"代码,或者代码从不离开调用堆栈并有效地绑定线程.如果总是在调用堆栈上执行代码,那么事件循环将永远不会将项目从回调队列推送到调用堆栈,并且它们永远不会被执行,从根本上冻结应用程序.这引出了我的下一个问题:

  1. 如果Javascript是由Chrome V8引擎解释的,那么"控制"将代码推送到回调队列上的是什么?如何通过libuv事件循环处理Javascript代码?

我发现这张图片是演示过程的一个例子:

在此输入图像描述

这是我不确定Chrome V8引擎和libuv如何互动的地方.我倾向于相信节点绑定有助于这种交互,但我不太确定如何.在上图中,似乎NodeJS绑定仅与通过V8从Javascript编译的机器代码进行交互.如果是这样,我感到困惑的是V8引擎如何解释Javascript,以便Node Bindings可以区分回调和实际代码以立即执行.

我知道这是一系列非常深刻和复杂的问题,但我相信这将有助于为试图理解Node.js的人们解决很多困惑,并帮助程序员理解事件驱动的优缺点,非基本级别的非阻塞IO.

状态更新:刚看过Sencha会议的精彩演讲(链接在这里).所以在这次演讲中,演示者提到了V8嵌入指南(此处链接),并讨论了如何将C++函数暴露给Javascript,反之亦然.本质上它是如何工作的是C++函数可以暴露给V8并且还指定它希望这些对象如何暴露给Javascript,并且V8解释器将能够识别嵌入式C++函数并在它找到与之匹配的Javascript时执行它们你指定了.例如,您可以将变量和函数公开给V8,这些变量和函数实际上是用C++编写的.这基本上是Node.js的作用; 它能够在requireJavascript中添加函数,这些函数在调用时实际执行C++代码.这稍微清除了问题1,但它并没有准确地显示Node标准库如何与V8一起工作.关于libuv如何与其中任何一个进行交互仍然不清楚.

javascript c++ v8 node.js libuv

24
推荐指数
1
解决办法
1501
查看次数

关于node.js内部异步I/O机制的困惑

  1. 我已经了解到node.js在内部使用libeio来执行异步文件 I/O,使用线程池,在*nix平台上,我是对的吗?
  2. 那么异步网络 I/O呢?它是由libev完成的吗?还有线程池吗?
  3. 如果内部有线程池,那么它如何比传统的每线程请求模型更高效?每个I/O请求是一个线程吗?
  4. Windows上的机制是什么?我知道它是由IOCP完成的,并且有一个内核级线程池,对吧?
  5. 为什么linux没有像Windows IOCP这样的本机完全AIO机制呢?它将来会有吗?

根据昌昌的回答更新:

  1. 我快速查看了@changchang给出的源代码,发现默认的线程池大小可以通过UV_THREADPOOL_SIZE重置,我想知道在哪种情况下会使用这个?
  2. 我还发现getaddrinfo使用这个线程池,除了fs还有更多吗?如果所有同步作业都将在此线程池中完成,那么默认大小"4"是否足够?
  3. 正如我现在的理解,node.js进程中将有6个基本线程:1个V8线程(事件循环,用户javascript代码运行),1个libuv事件循环,4个线程池,我是对的吗?
  4. 我怎样才能在shell(Ubuntu)中看到这些线程?我用ps -eLf | grep节点| grep -v grep只看到两个:

    root 16148 7492 16148 0 2 20:43 pts/26 00:00:00 ./bin/node /home/aaron/workspace/test.js
    root 16148 7492 16149 0 2 20:43 pts/26 00:00:00./bin/node /home/aaron/workspace/test.js

javascript linux io node.js libuv

23
推荐指数
1
解决办法
6509
查看次数

Node实际创建了多少个线程?

在阅读关于Node的线程性质的这个很好的答案后,我开始使用UV_THREADPOOL_SIZE系统变量来改变线程池的大小,我发现了一些有趣的东西:

当我设置

process.env.UV_THREADPOOL_SIZE = 10;
Run Code Online (Sandbox Code Playgroud)

我的Node进程中有15个线程(我认为它应该是10 + 1主节点线程= 11).

看看我的剧本:

process.env.UV_THREADPOOL_SIZE = 10;

//init thread pool by calling `readFile` function
require('fs').readFile(__filename, 'utf8', function(err, content) {});

//make node not exiting
setInterval(function() {}, 1000);
Run Code Online (Sandbox Code Playgroud)

运行后我输入:

ps -Lef | grep test.js | grep -v grep
Run Code Online (Sandbox Code Playgroud)

并获得以下结果:

olegssh   4869  4301  4869  0   15 16:38 pts/0    00:00:00 /home/olegssh/node/bin/node test.js
olegssh   4869  4301  4870  0   15 16:38 pts/0    00:00:00 /home/olegssh/node/bin/node test.js
olegssh   4869  4301  4871  0   15 16:38 pts/0    00:00:00 …
Run Code Online (Sandbox Code Playgroud)

multithreading threadpool node.js libuv

22
推荐指数
1
解决办法
3677
查看次数

libuv线程安全吗?

我创建了一个专门用于libuv运行循环的新线程.线程函数看起来像这样:

void thread_function()
{
  uv_loop_t *loop = uv_loop_new();
  uv_ref( loop );
  uv_run( loop );
}
Run Code Online (Sandbox Code Playgroud)

ref计数器增量使线程保持活动状态并处于处理libuv事件的状态.我希望能够通过uv_unref在主线程上执行来导致运行循环结束,从而导致线程退出.

但是,在检查uv_ref源代码时,我没有看到任何保证在并发访问期间将同步对引用计数器变量的访问.另外,我没有看到在运行循环期间放弃对操作系统的控制的任何良率调用,这意味着程序将不能与其他进程很好地协作.

这让我相信我没有以正确的方式使用libuv.如果有人能解释我做错了什么,那就太好了!

c++ pthreads node.js libuv

16
推荐指数
1
解决办法
5370
查看次数

"EXDEV:跨设备链接不允许"错误是什么意思?

这个错误究竟意味着什么?什么是"跨设备链接"?

此libuv页面上提到它,但除了"不允许交叉设备链接"之外,它不提供任何详细信息.

node.js libuv

16
推荐指数
3
解决办法
2万
查看次数

从V8中的C++回调调用Javascript函数

我正在尝试在调用c ++回调时调用已注册的JS函数,但我得到了一个段错误,我认为这是一个范围问题.

 Handle<Value> addEventListener( const Arguments& args ) {
    HandleScope scope;
    if (!args[0]->IsFunction()) {
        return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
    }

    Persistent<Function> fn = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
    Local<Number> num = Number::New(registerListener(&callback, &fn));
    scope.Close(num);
}
Run Code Online (Sandbox Code Playgroud)

发生事件时,将调用以下方法.我假设这可能发生在V8正在执行JS的另一个线程上.

void callback(int event, void* context ) {
    HandleScope scope;
    Local<Value> args[] = { Local<Value>::New(Number::New(event)) };
    Persistent<Function> *func = static_cast<Persistent<Function> *>(context);
    (* func)->Call((* func), 1, args);

    scope.Close(Undefined());
}
Run Code Online (Sandbox Code Playgroud)

这会导致分段错误:11.请注意,如果我直接使用addEventListener()对Persistent的引用来调用回调函数,它会正确执行该函数.

我假设我需要一个储物柜或隔离物?它看起来像libuv的uv_queue_work()可能能够解决这个问题,但由于我没有启动该线程,我看不出你将如何使用它.

c++ multithreading v8 libuv

13
推荐指数
2
解决办法
8036
查看次数

C优化:条件存储,以避免弄脏缓存行

libuv源代码中,我找到了这段代码:

  /* The if statement lets the compiler compile it to a conditional store.
   * Avoids dirtying a cache line.
   */
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;
Run Code Online (Sandbox Code Playgroud)

有人能解释一下吗?

什么是缓存行?

另外,我猜条件存储是一些汇编指令,它检查一些东西,如果成功,写一些值.对?

这种结构什么时候有意义?我想并不总是,因为否则编译器会一直使用条件存储,对吧?

c libuv

11
推荐指数
1
解决办法
414
查看次数

为什么stdout缓冲?

我正在尝试学习libuvapi并编写以下测试:

#include <stdio.h>
#include <stdlib.h>
#include <uv.h>

void timer_cb(uv_timer_t* timer) {
    int* i = timer->data;
    --*i;
    if(*i == 0) {
       uv_timer_stop(timer);
    }
    printf("timer %d\n", *i);
    //fflush(stdout);
}

int main() {
    uv_loop_t* loop = uv_default_loop();
    uv_timer_t* timer = malloc(sizeof(uv_timer_t));
    uv_timer_init(loop, timer);
    int i = 5;
    timer->data = &i;
    uv_timer_start(timer, timer_cb, 1000, 2000);

    uv_run(loop, UV_RUN_DEFAULT);

    printf("Now quitting.\n");
    uv_close(timer, 0);
    uv_loop_close(loop);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

运行它时,在程序完成运行之前不会显示任何输出,然后立即显示所有输出.如果我取消注释fflush它按预期工作,则每2秒写一次.

有人可以向我解释一下吗?为什么stdout如解释不换行后刷新,在这里和在其他地方?为什么我需要手动冲洗它?

c libuv

11
推荐指数
2
解决办法
2169
查看次数

libuv:如何在错误上优雅地退出应用程序?

我有一个使用libuv库的应用程序.它运行默认循环:

uv_run(uv_default_loop());
Run Code Online (Sandbox Code Playgroud)

如果发生故障,如何正常退出应用程序?目前我正在这样做,如下例所示:

uv_tcp_t* tcp = malloc(sizeof(uv_tcp_t));
int r = uv_tcp_init(uv_default_loop(), tcp);

if (r) {
  free(tcp);
  uv_loop_delete(default_loop);
  exit(EXIT_FAILURE);
}
Run Code Online (Sandbox Code Playgroud)

应该uv_loop_delete调用函数吗?它有什么作用?它是否会丢弃所有待处理的回调函数?它是否关闭所有当前打开的TCP连接?退出前我是否必须手动完成?

PS:无法添加标签'libuv'(声誉低于1500).有人可以创建并添加它吗?

c nonblocking exit libuv

10
推荐指数
1
解决办法
2107
查看次数

标签 统计

libuv ×10

node.js ×5

c++ ×4

c ×3

javascript ×2

multithreading ×2

v8 ×2

boost ×1

boost-asio ×1

exit ×1

io ×1

linux ×1

nonblocking ×1

pthreads ×1

threadpool ×1