Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库

libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;

libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;

libuv :开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;

Libuv 基础

libuv 采用了 异步 (asynchronous), 事件驱动 (event-driven)的编程风格, 其主要任务是为开人员提供了一套事件循环和基于I/O(或其他活动)通知的回调函数, libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能.

事件循环(Event loops)

在事件编程模型中, 应用程序通常会关注某些特定的事件, 并在事件发生后对其作出响应. 而收集事件或监控其他事件源则是 libuv 的职责, 编程人员只需要对感兴趣的事件注册回调函数, 在事件发生后 libuv 将会调用相应的回调函数. 只要程序不退出(被系统管理人员 kill 掉), 事件循环通常会一直运行, 下面是事件驱动编程模型的伪代码:

while there are still events to process:e = get the next eventif there is a callback associated with e:call the callback

适用于事件驱动编程模型的例子如下:

  • 文件已经准备好可写入数据.
  • 某一 socket 上存在数据可读.
  • 定时器已超时.

事件循环由 uv_run 函数封装, 在使用 libuv 编程时, 该函数通常在最后才被调用.

计算机程序最基本的活动是输入输出的处理, 而不是大量的数值计算, 而使用传统输入输出函数(read, fprintf 等)的问题是它们都是 阻塞 的. 将数据写入磁盘或者从网络读取数据都会消耗大量时间, 而阻塞函数直到任务完成后才返回, 在此期间你的程序什么也没有做, 浪费了大量的 CPU 时间. 对于追求高性能的程序而言, 在其他活动或者 I/O 操作在进行尽量让 CPU 不被阻塞.

标准的解决方案是使用线程, 每个阻塞的 I/O 操作都在一个单独的线程(或线程池)中启动, 当阻塞函数被调用时, 处理器可以调度另外一个真正需要 CPU 的线程来执行任务.

Libuv 采用另外一种方式处理阻塞任务, 即 异步 和 非阻塞 方式.大多数现代操作系统都提供了事件通知功能, 例如, 调用 read 读取网络套接字时程序会阻塞, 直到发送者最终发送了数据(read 才返回). 但是, 应用程序可以要求操作系统监控套接字, 并在套接字上注册事件通知. 应用程序可以在适当的时候查看它所监视的事件并获取数据(若有). 整个过程是 异步 的, 因为程序在某一时刻关注了它感兴趣的事件, 并在另一个时刻获取(使用)数据, 这也是 非阻塞 的, 因为该进程还可以处理另外的任务. Libuv 的事件循环方式很好地与该模型匹配, 因为操作系统事件可以视为另外一种 libuv 事件. 非阻塞方式可以保证在其他事件到来时被尽快处理 [1].

Note

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

Hello World

具备了上面最基本的知识后, 我们就来编写一个简单 libuv 的程序吧.该程序并没有做任何具体的事情, 只是简单的启动了一个会退出的事件循环.

#include <stdio.h>
#include <uv.h>int main() {uv_loop_t *loop = uv_loop_new();printf("Now quitting.\n");uv_run(loop, UV_RUN_DEFAULT);return 0;
}

该程序启动后就会直接退出, 因为你没有事件可处理. 我们可以使用 libuv 提供了各种 API 来告知 libuv 我们感兴趣的事件.

libuv 的默认事件循环(Default loop)

libuv 提供了一个默认的事件循环, 你可以通过 uv_default_loop 来获得该事件循环, 如果你的程序中只有一个事件循环, 你就应该使用 libuv 为我们提供的默认事件循环.

Note

node.js 使用默认事件循环作为它的主循环,如果你正在编写 node.js 的绑定, 你应该意识到这一点.

监视器(Watchers)

libuv 通过监视器(Watcher)来对特定事件进行监控, 监视器通常是类似 uv_TYPE_t 结构体的封装, TYPE 代表该监视器的用途, libuv 所有的监视器类型如下:

typedef struct uv_loop_s uv_loop_t;
typedef struct uv_err_s uv_err_t;
typedef struct uv_handle_s uv_handle_t;
typedef struct uv_stream_s uv_stream_t;
typedef struct uv_tcp_s uv_tcp_t;
typedef struct uv_udp_s uv_udp_t;
typedef struct uv_pipe_s uv_pipe_t;
typedef struct uv_tty_s uv_tty_t;
typedef struct uv_poll_s uv_poll_t;
typedef struct uv_timer_s uv_timer_t;
typedef struct uv_prepare_s uv_prepare_t;
typedef struct uv_check_s uv_check_t;
typedef struct uv_idle_s uv_idle_t;
typedef struct uv_async_s uv_async_t;
typedef struct uv_process_s uv_process_t;
typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_fs_poll_s uv_fs_poll_t;
typedef struct uv_signal_s uv_signal_t;

所有监视器的结构都是 uv_handle_t 的”子类”, 在 libuv 和本文中都称之为句柄( handlers ).

监视器由相应类型的初始化函数设置, 如下:

uv_TYPE_init(uv_TYPE_t*) 

某些监视器初始化函数的第一个参数为事件循环的句柄.

监视器再通过调用如下类型的函数来设置事件回调函数并监听相应事件:

uv_TYPE_start(uv_TYPE_t*, callback) 

而停止监听应调用如下类型的函数:

uv_TYPE_stop(uv_TYPE_t*) 

当 libuv 所监听事件发生后, 回调函数就会被调用. 应用程序特定的逻辑通常都是在回调函数中实现的, 例如, 定时器回调函数在发生超时事件后也会被调用, 另外回调函被调用时传入的相关参数都与特定类型的事件有关, 例如, IO 监视器的回调函数在发生了IO事件后将会收到从文件读取的数据.

空转(Idling)

接下来我们通过例子来讲述监视器的使用. 例子中空转监视器回调函数被不断地重复调用, 当然其中也有一些深层次的语言,我们将会在 工具集 进一步讨论, 但现在我们只是跳过具体细节. 我们只是使用了一个空转监视器回调来看看监视器的生命周期, 通过例子我们也可以了解到: 由于设置了监视器, 所以调用 uv_run() 是程序会阻塞, 空转监视器将会在计数器达到设定的值时停止(监视), uv_run() 会退出因为此时程序中没有活动的监视器了.

#include <stdio.h>
#include <uv.h>int64_t counter = 0;void wait_for_a_while(uv_idle_t* handle, int status) {counter++;if (counter >= 10e6)uv_idle_stop(handle);
}int main() {uv_idle_t idler;uv_idle_init(uv_default_loop(), &idler);uv_idle_start(&idler, wait_for_a_while);printf("Idling...\n");uv_run(uv_default_loop(), UV_RUN_DEFAULT);return 0;
}

Libuv 介绍(一)相关推荐

  1. libuv介绍与编译

    libuv介绍 一.简介 1.开源跨平台的异步IO库(网络异步.文件异步等),它是node.js的底层库. 2.官方网站:http://libuv.org. 3.事件循环模型:IOCP.epoll.k ...

  2. libuv介绍和实现的基本流程

    文章目录 前言 一.libuv核心是什么? 二.libuv简单介绍 1.简单实现 2.监视器 3.handle的通用API 总结 前言 libuv是一个高性能的,事件驱动的I/O库,并且提供了跨平台( ...

  3. Unity基础学习路线

        Unity基础 C#程序设计 第001课初识unity 第002课初始unity场景树_渲染体系_物理体系 第003课初识Unity C#的基本结构_类_成员_类的函数 第004课Unity ...

  4. [转]为什么我要用 Node.js? 案例逐一介绍

    原文地址:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  5. libuv 中文编程指南(零)前言

    最近看了一些有关 libuv 的东西,另外复习了一些与同步.异步.阻塞.非阻塞,异步IO(aio)的东西, 算是技术积累吧,等有时间了整理出一个完整的文档出来,希望在今后的编程中用到. 不多说了,本文 ...

  6. libuv 高性能 事件驱动 跨平台 i/o库 简介

    目录 1.Introduction 简介 Who this book is for Background Code 2.Basics of libuv libuv基础 Event loops HELL ...

  7. libuv 高性能事件驱动库 简介

    libuv是一个高性能事件驱动库,屏蔽了各种操作系统的差异从而提供了统一的API.libuv严格使用异步.事件驱动的编程风格.其核心工作是提供事件循环及基于 I/O或其他活动事件的回调机制.libuv ...

  8. libuv 中文编程指南

    最近看了一些有关 libuv 的东西,另外复习了一些与同步.异步.阻塞.非阻塞,异步IO(aio)的东西, 算是技术积累吧,等有时间了整理出一个完整的文档出来,希望在今后的编程中用到. 不多说了,本文 ...

  9. linux下编译libuv,linux下libuv库安装教程

    下载并编译libuv libuv需要自己手动下载源码,并手动编译. 当前目录为:/home/xlz/test/github/,在后面,会用$PATH来代替,我的系统的Debian8,64bit. $g ...

最新文章

  1. spring 下载地址
  2. 如何配置 SQL Server 2005 以允许远程连接
  3. [云炬创业基础笔记] 第四章测试2
  4. 网易云信+妙克:从零到标杆的在线音视频音乐教学之路
  5. 知识工场 | 知识图谱暑假班开始报名啦!
  6. sharepoint 2010 彻底删除用户
  7. linux虚拟地址被大量占用,《Linux中为什么要使用虚拟地址》
  8. MySQL8的inodb参数设置_MySQL8.0自适应参数innodb_dedicated_server
  9. 216. 组合总和 III017(回溯法求解)
  10. 前端学习(2587):权限控制的分类和意义
  11. case when then的用法
  12. python反射详解
  13. MFC源码解读(一)最原始一个MFC程序,手写不用向导
  14. FFmpeg--命令详解
  15. Sublime 下配置vim模式 + VintageEx-master下载地址
  16. 042 实例10-文本词频统计
  17. linux系统安装红蜘蛛,在linux Deepin深度系统安装多媒体电子教室Veyon
  18. C# 如何插入、删除Excel分页符
  19. 初中生物教师资格证经验贴
  20. Cortex M4 SVC 中断

热门文章

  1. 史上最贱游戏(附攻略)
  2. brower-sync 解决webstorm不兼容
  3. hadoop分布式框架_蔡玉池
  4. 带字幕的Youtube
  5. 企业年会直播方案,看完这份就够了
  6. 蜂鸟金融终端:零滞后技术指标
  7. Python爬虫学习第十一天---pymongo模块使用
  8. vue.js自定义LCD字体及字体压缩
  9. vdo(虚拟数据优化)
  10. CCD-影像增强器 到 平板探测器的趋势