Libuv教程
+ -

Libuv 工作原理

2019-09-09 0 0

libuv强制使用异步事件驱动的编程风格。它的核心工作是提供一个event-loop,还有基于I/O和其它事件通知的回调函数。
libuv还提供了一些核心工具,例如定时器,非阻塞的网络支持,异步文件系统访问,子进程等。

Event loops


在事件驱动编程中,程序会关注每一个事件,并且对每一个事件的发生做出反应。
libuv会负责将来自操作系统的事件收集起来,或者监视其他来源的事件。这样,用户就可以注册回调函数,回调函数会在事件发生的时候被调用。
event-loop会一直保持运行状态。用伪代码描述如下:

while there are still events to process:
    e = get the next event                        //回调事件
    if there is a callback associated with e: //是否有回调与事件关调
        call the callback                      //调用回谳函数

举几个事件的例子:

  • 准备好被写入的文件。
  • 包含准备被读取的数据的socket。
  • 超时的定时器。

event-loop最终会被uv_run()启动-当使用libuv时,最后都会调用的函数。

libuv的IO解决方案

系统编程中最经常处理的一般是输入和输出,而不是一大堆的数据处理。问题在于传统的输入/输出函数(例如read,fprintf)都是阻塞式的。实际上,向文件写入数据,从网络读取数据所花的时间,对比CPU的处理速度差得太多。任务没有完成,函数是不会返回的,所以你的程序在这段时间内什么也做不了。对于需要高性能的的程序来说,这是一个主要的障碍因为其他活动和I/O操作都在保持等待。

其中一个标准的解决方案是使用多线程。每一个阻塞的I/O操作都会被分配到各个线程中(或者是使用线程池)。当某个线程一旦阻塞,处理器就可以调度处理其他需要cpu资源的线程。

但是libuv使用了另外一个解决方案,那就是异步,非阻塞风格。大多数的现代操作系统提供了基于事件通知的子系统。
例如,一个正常的socket上的read调用会发生阻塞,直到发送方把信息发送过来。但是,实际上程序可以请求操作系统监视socket事件的到来,并将这个事件通知放到事件队列中。这样,程序就可以很简单地检查事件是否到来(可能此时正在使用cpu做数值处理的运算),并及时地获取数据。说libuv是异步的,是因为程序可以在一头表达对某一事件的兴趣,并在另一头获取到数据(对于时间或是空间来说)。它是非阻塞是因为应用程序无需在请求数据后等待,可以自由地做其他的事。libuv的事件循环方式很好地与该模型匹配, 因为操作系统事件可以视为另外一种libuv事件. 非阻塞方式可以保证在其他事件到来时被尽快处理(当然还要考虑硬件的能力)。

注意:

我们不需要关心I/O在后台是如何工作的,但是由于我们的计算机硬件的工作方式,线程是处理器最基本的执行单元,libuv和操作系统通常会运行后台/工作者线程, 或者采用非阻塞方式来轮流执行任务。

Bert Belder,一个libuv的核心开发者,通过一个短视频向我们解释了libuv的架构和它的后台工作方式。如果你之前没有接触过类似libuv,libev,这个视频会非常有用。视频的网址是https://youtu.be/nGn60vDSxQ4

HELLO WORLD

helloworld/main.c

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

int main() {
    uv_loop_t *loop = malloc(sizeof(uv_loop_t));
    uv_loop_init(loop);

    printf("Now quitting.\n");
    uv_run(loop, UV_RUN_DEFAULT);

    uv_loop_close(loop);
    free(loop);
    return 0;
}

远行这个程序会很快就退出了,因为没有可以很处理的事件。我们可以使用各种API函数来告诉event-loop我们要监视的事件。

从libuv的1.0版本开始,用户就可以在使用uv_loop_init初始化loop之前,给其分配相应的内存。这就允许你植入自定义的内存管理方法。记住要使用uv_loop_close(uv_loop_t *)关闭loop,然后再回收内存空间。在例子中,程序退出的时候会关闭loop,系统也会自动回收内存。对于长时间运行的程序来说,合理释放内存很重要。

包含了libuv的event-loop的更多详细信息的文档

Default loop

可以使用uv_default_loop获取libuv提供的默认loop。如果你只需要一个loop的话,可以使用这个。

注意:

nodejs中使用了默认的loop作为自己的主loop。如果你在编写nodejs的绑定,你应该注意一下。

0 篇笔记 写笔记

Libuv 工作原理
libuv强制使用异步和事件驱动的编程风格。它的核心工作是提供一个event-loop,还有基于I/O和其它事件通知的回调函数。libuv还提供了一些核心工具,例如定时器,非阻塞的网络支持,异步文件系统访问,子进程等。Event loops在事件驱动编程中,程序会关注每一个事件,并且对每一个事件的发......
Libuv TCP工作原理
libuv tcp结构体之间关系在使用TCP时,常常使用结构体uv_tcp_t和uv_stream_t。它们之间的关系是uv_tcp_t包含uv_stream_t。typedef struct uv_stream_s uv_stream_t;typedef struct uv_tcp_s uv_tc......
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!