libuv库学习笔记-basics_of_libuv
Basics of libuv
libuv强制使用异步和事件驱动的编程风格。它的核心工作是提供一个event-loop,还有基于I/O和其它事件通知的回调函数。libuv还提供了一些核心工具,例如定时器,非阻塞的网络支持,异步文件系统访问,子进程等。
Event loops
在事件驱动编程中,程序会关注每一个事件,并且对每一个事件的发生做出反应。libuv会负责将来自操作系统的事件收集起来,或者监视其他来源的事件。这样,用户就可以注册回调函数,回调函数会在事件发生的时候被调用。event-loop会一直保持运行状态。用伪代码描述如下:
while there are still events to process:e = get the next eventif there is a callback associated with e:call the callback
举几个事件的例子:
- 准备好被写入的文件。
- 包含准备被读取的数据的socket。
- 超时的定时器。
event-loop最终会被uv_run()启动-当使用libuv时,最后都会调用的函数。
系统编程中最经常处理的一般是输入和输出,而不是一大堆的数据处理。问题在于传统的输入/输出函数(例如read,fprintf)都是阻塞式的。实际上,向文件写入数据,从网络读取数据所花的时间,对比CPU的处理速度差得太多。任务没有完成,函数是不会返回的,所以你的程序在这段时间内什么也做不了。对于需要高性能的的程序来说,这是一个主要的障碍因为其他活动和I/O操作都在保持等待。
其中一个标准的解决方案是使用多线程。每一个阻塞的I/O操作都会被分配到各个线程中(或者是使用线程池)。当某个线程一旦阻塞,处理器就可以调度处理其他需要cpu资源的线程。
但是libuv使用了另外一个解决方案,那就是异步,非阻塞风格。大多数的现代操作系统提供了基于事件通知的子系统。例如,一个正常的socket上的read调用会发生阻塞,直到发送方把信息发送过来。但是,实际上程序可以请求操作系统监视socket事件的到来,并将这个事件通知放到事件队列中。这样,程序就可以很简单地检查事件是否到来(可能此时正在使用cpu做数值处理的运算),并及时地获取数据。说libuv是异步的,是因为程序可以在一头表达对某一事件的兴趣,并在另一头获取到数据(对于时间或是空间来说)。它是非阻塞是因为应用程序无需在请求数据后等待,可以自由地做其他的事。libuv的事件循环方式很好地与该模型匹配, 因为操作系统事件可以视为另外一种libuv事件. 非阻塞方式可以保证在其他事件到来时被尽快处理(当然还要考虑硬件的能力)。
Note
我们不需要关心I/O在后台是如何工作的,但是由于我们的计算机硬件的工作方式,线程是处理器最基本的执行单元,libuv和操作系统通常会运行后台/工作者线程, 或者采用非阻塞方式来轮流执行任务。
Bert Belder,一个libuv的核心开发者,通过一个短视频向我们解释了libuv的架构和它的后台工作方式。如果你之前没有接触过类似libuv,libev,这个视频会非常有用。视频的网址是https://youtu.be/nGn60vDSxQ4 。
包含了libuv的event-loop的更多详细信息的文档。
HELLO WORLD
让我们开始写第一个libuv程序吧!它什么都没做,只是开启了一个loop,然后很快地退出了。
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,系统也会自动回收内存。对于长时间运行的程序来说,合理释放内存很重要。
Default loop
可以使用uv_default_loop获取libuv提供的默认loop。如果你只需要一个loop的话,可以使用这个。
Note
nodejs中使用了默认的loop作为自己的主loop。如果你在编写nodejs的绑定,你应该注意一下。
Error handling
初始化函数或者同步执行的函数,会在执行失败后返回代表错误的负数。但是对于异步执行的函数,会在执行失败的时候,给它们的回调函数传递一个状态参数。错误信息被定义为UV_E*常量。
你可以使用uv_strerror(int)和uv_err_name(int)分别获取const char *格式的错误信息和错误名字。
I/O函数的回调函数(例如文件和socket等)会被传递一个nread参数。如果nread小于0,就代表出现了错误(当然,UV_EOF是读取到文件末端的错误,你要特殊处理)。
##Handles and Requests
libuv的工作建立在用户表达对特定事件的兴趣。这通常通过创造对应I/O设备,定时器,进程等的handle来实现。handle是不透明的数据结构,其中对应的类型uv_TYPE_t中的type指定了handle的使用目的。
libuv watchers
/* Handle types. */
typedef struct uv_loop_s uv_loop_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;/* Request types. */
typedef struct uv_req_s uv_req_t;
typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
typedef struct uv_getnameinfo_s uv_getnameinfo_t;
typedef struct uv_shutdown_s uv_shutdown_t;
typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
typedef struct uv_udp_send_s uv_udp_send_t;
typedef struct uv_fs_s uv_fs_t;
typedef struct uv_work_s uv_work_t;/* None of the above. */
typedef struct uv_cpu_info_s uv_cpu_info_t;
typedef struct uv_interface_address_s uv_interface_address_t;
typedef struct uv_dirent_s uv_dirent_t;
handle代表了持久性对象。在异步的操作中,相应的handle上有许多与之关联的request。request是短暂性对象(通常只维持在一个回调函数的时间),通常对映着handle上的一个I/O操作。Requests用来在初始函数和回调函数之间,传递上下文。例如uv_udp_t代表了一个udp的socket,然而,对于每一个向socket的写入的完成后,都会向回调函数传递一个uv_udp_send_t。
handle可以通过下面的函数设置:
uv_TYPE_init(uv_loop_t *, uv_TYPE_t *)
回调函数是libuv所关注的事件发生后,所调用的函数。应用程序的特定逻辑会在回调函数中实现。例如,一个IO监视器的回调函数会接收到从文件读取到的数据,一个定时器的回调函数会在超时后被触发等等。
Idling
下面有一个使用空转handle的例子。回调函数在每一个循环中都会被调用。在Utilities这部分会讲到一些空转handle的使用场景。现在让我们使用一个空转监视器,然后来观察它的生命周期,接着看uv_run调用会造成阻塞。当达到事先规定好的计数后,空转监视器会退出。因为uv_run已经找不到活着的事件监视器了,所以uv_run()也退出。
idle-basic/main.c
#include <stdio.h>
#include <uv.h>int64_t counter = 0;void wait_for_a_while(uv_idle_t* handle) {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);uv_loop_close(uv_default_loop());return 0;
}
Storing context
在基于回调函数的编程风格中,你可能会需要在调用处和回调函数之间,传递一些上下文等特定的应用信息。所有的handle和request都有一个data域,可以用来存储信息并传递。这是一个c语言库中很常见的模式。即使是uv_loop_t也有一个相似的data域。
相关文章:
libuv库学习笔记-basics_of_libuv
Basics of libuv libuv强制使用异步和事件驱动的编程风格。它的核心工作是提供一个event-loop,还有基于I/O和其它事件通知的回调函数。libuv还提供了一些核心工具,例如定时器,非阻塞的网络支持,异步文件系统访问,子进…...
【Vuvuzela 声音去噪算法】基于流行的频谱减法技术的声音去噪算法研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Vue + Element-ui组件上传图片报错问题解决方案
在前端开发中,我们经常需要模拟网络请求以进行单元测试或开发调试。而在模拟网络请求时,我们常常会使用到MockXMLHttpRequest对象。MockXMLHttpRequest对象是一个用于模拟XMLHttpRequest对象的工具,它提供了一种简单的方式来模拟网络请求&…...
java商城系统和php商城系统对比
java商城系统和php商城系统是两种常见的电子商务平台,它们都具有一定的优势和劣势。那么,java商城系统和php商城系统又有哪些差异呢? 一、开发难度 Java商城系统和PHP商城系统在开发难度方面存在一定的差异。Java商城系统需要使用Java语言进…...
某制造企业基于 KubeSphere 的云原生实践
背景介绍 随着业务升级改造与软件产品专案的增多,常规的物理机和虚拟机方式逐渐暴露出一些问题: 大量服务部署在虚拟机上,资源预估和硬件浪费较大;大量服务部署在虚拟机上,部署时间和难度较大,自动化程度…...
Electron 学习_BrowserWindow
BrowserWindow创建并控制浏览器窗口(主进程) 条件:在 app 模块 emitted ready 事件之前,您不能使用此模块。 1.在加载页面时,渲染进程第一次完成绘制时,如果窗口还没有被显示,渲染进程会发出 ready-to-show 事件 。 在…...
Docker学习笔记,包含docker安装、常用命令、dockerfile、docker-compose等等
😀😀😀创作不易,各位看官点赞收藏. 文章目录 Docker 学习笔记1、容器2、Docker 安装3、Docker 常用命令4、Docker 镜像5、自定义镜像5.1、镜像推送到阿里云5.2、镜像私有库 6、数据卷7、Docker 软件安装8、Docker File8.1、常见保…...
解决 “Module build failed (from ./node_modules/babel-loader/lib/index.js)“ 错误的方法
系列文章目录 文章目录 系列文章目录前言一、错误原因:二、解决方法:三、注意事项:总结 前言 在前端项目开发中,如果使用了 Babel 来转译 ES6 语法,有时会遇到错误信息 “Module build failed (from ./node_modules/b…...
go学习 6、方法
6、方法 面向对象编程(OOP),封装、组合。 6.1 方法声明 在函数声明时,在其名字之前放上一个变量,即是一个方法。这个附加的参数会将该函数附加到这种类型上,即相当于为这种类型定义了一个独占的方法。 …...
MySQL Windows版本下载及安装时默认路径的修改
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、MySQL 下载二、默认路径修改1、安装前准备【非常重要】2、启动安装程序总结1、MySQL下载2、MySQL默认路径修改前言 MySQL 被Oracle收购后,各种操作规范及约束也相应的跟着来了,这不,只…...
第3章 配置与服务
1 CoreCms.Net.Configuration.AppSettingsHelper using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; namespace CoreCms.Net.Configuration { /// <summary> /// 【应用设置助手--类】 /// <remarks> /// 摘要&#x…...
Arcgis之 KML/KMZ文件转shp
一般我们在Goole Earth上勾画的区域导出后都为KML或者KMZ格式的,但无法在arcgis等软件上直接应用,故需进行一定的转换 1.打开ArcMap,选择ArcToolbox->Conversion Tools->From KML->KML To Layer 得到如下结果(由于本KML…...
python绘制3D条形图
文章目录 数据导入三维条形图bar3d 数据导入 尽管在matplotlib支持在一个坐标系中绘制多组条形图,效果如下 其中,蓝色表示中国,橘色表示美国,绿色表示欧盟。从这个图就可以非常直观地看出,三者自2018到2022年的GDP变化…...
计算从曲线的起点到param指定的点的曲线段的长度
以下方法只能用于继承于AcDbCurve的类型 主要使用两个接口 派生类中此函数的实现应返回, 并将endParam设置为曲线端点的参数。 如果成功则返回Acad::eOk。 默认情况下, 该函数返回Acad::eNotImplemented。 virtual Acad::ErrorStatus getEndParam(double&endParam) cons…...
POLARDB IMCI 白皮书 云原生HTAP 数据库系统 一 数据压缩和打包处理与数据更新
开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共…...
linux----源码安装如何加入到系统服务中(systemclt)
将自己源码安装的软件加入到系统服务中。例如nginx,mysql 就以nginx为例,源码安装,加入到系统服务中 使用yum安装nginx,自动会加入到系统服务 16-Linux系统服务 - 刘清政 - 博客园 (cnblogs.com) 第一步: 源码安装好nginx之后࿰…...
Unity 使用UnityWebRequest 读取存档 (IOS只能这样做)
打IOS包的时候发现的,不能使用正常的IO流读取,不然会读取不到数据,只能使用UnityWebRequest 读取 代码如下 public IEnumerator ReadArchive(Action<bool, string> ac, string filepath ""){UnityWebRequest request Unit…...
Caused by: org.springframework.beans.factory.
问题解决:Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name IUserRepository defined in app.test4.OpportunityMatching.IUserRepository defined in EnableJpaRepositories declared on JpaRepositoriesRegistrar.Enable…...
【docker 安装】 与【docker-compose 安装】
不同的操作系统需要不同的docker安装文件:具体下载位置: Docker: https://download.docker.com/linux/static/stable/ docekr-compose:https://github.com/docker/compose/releases 1. 验证客户机器是否有docker 和docker-compose docker -…...
意外:WPS编程新工具,不用编程,excel用户:可以不用VBA啦
来来来,拓宽一下视野! 别总以为excel和WPS只能用VBA编程,也别总是想着ACCESS这些老生常谈的工具。其实对于电子表格高级用户来讲,不会VBA,不用ACCESS,也一样可以解决复杂问题或者高级应用。 尤其是WPS用户…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
