零拷贝技术(zero copy),DMA,mmap,sendfile

news2024/11/25 5:20:14

在一些高性能的IO场景下我们经常能听到零拷贝技术,这是个不错的话题。

零拷贝指的是内核态与用户态之间的数据拷贝,而这两个区域的数据拷贝只能依靠CPU,但是CPU最重要的作用应该是运算。

一、DMA的由来

在没有DMA之前,磁盘的IO是这样的。

在这里插入图片描述

  • 用户进程调用read操作,CPU收到指令后,发出对应的指令给磁盘控制器,然后返回。
  • 磁盘控制器收到指令后,于是就开始准备数据,会把数据放入到磁盘控制器的内部缓冲区中,然后产生一个中断。
  • CPU收到中断信号后,停下手头的工作,接着把磁盘控制器的缓冲区的数据一次一个字节地读进自己的寄存器,然后再把寄存器里的数据写入到内存,而在数据传输的期间CPU 是无法执行其他任务的。

可以看到整个过程占用了大量的CPU时间,如果数据量大的话那整个的性能将不敢想象。

如果将这种搬运数据的工作交给单独的组件来执行,那么就可以解放CPU,使其专注于运算。于是就有了 DMA (直接内存访问 Direct Memory Access),顾名思义,就是允许外部设备直接读写内存,既不通过CPU,也不需要CPU干预。主存和DMA控制器之间有一条数据通路,因此主存和I/O设备之间交换信息时,不通过CPU。在数据块传送时,主存地址的确定、传送数据的计数等都由外设的硬件电路直接实现。主存中要开辟专用缓冲区,及时供给和接收外设的数据。

有了DMA之后传输数据就变成了
在这里插入图片描述

二、文件传输案例

在不适用任何零拷贝技术的情况下,我们将一个文件从服务器上发送给客户端的过程大致如下。

在这里插入图片描述

要经过两次系统调用(read & write)加四次数据拷贝,而每次系统调用都有两次用户态和内核态的切换。具体看图。

三、如何实现零拷贝

1、mmap (memory-map)

它可以把文件映射到进程的虚拟内存空间。通过对这段内存的读取和修改,可以实现对文件的读取和修改,而不需要用read和write系统调用,但是这一切都需要操作系统在幕后工作(异步处理)。如下图所示,为mmap实现原理的示意图。

在这里插入图片描述

可以看到,用户进程空间中某一块虚拟内存与内核中的物理内存(PageCache)形成映射,而这块物理内存与目标文件的某一块形成映射。用户进程读取文件的过程不是传统的read系统调用,而是直接访问的PageCache,如果没有数据,系统会把文件的内容读取过来缓存起来,应该说就是利用的内核中的缓存区。

为什么传统的read操作会有一个从内核缓存中把数据拷贝到用户态的操作呢,我的理解是,内核态中的数据属于高速缓存,在有效期内它可以被重复读取,向用户态中拷贝一份也是方便各自程序区处理数据,形成隔离效果。

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

addr:指定映射的起始地址,通常设为NULL,由内核来分配
length:代表将文件中映射到内存的部分的长度。
prot:映射区域的保护方式。可以为以下几种方式的组合:
    PROT_EXEC 映射区域可被执行
    PROT_READ 映射区域可被读取
    PROT_WRITE 映射区域可被写入
    PROT_NONE 映射区域不能存取
flags:映射区的特性标志位,常用的两个选项是:
    MAP_SHARD:写入映射区的数据会复制回文件,且运行其他映射文件的进程共享
    MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制,对此区域的修改不会写会原文件
fd:要映射到内存中的文件描述符,有open函数打开文件时返回的值。
offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
函数返回值:实际分配的内存的起始地址。

与mmap函数成对使用的是munmap函数,它是用来解除映射的函数

int munmap(void *start, size_t length)
    
start:映射的起始地址
length:文件中映射到内存的部分的长度
返回值:解除成功返回0,失败返回-1
package main

import (
	"fmt"

	"golang.org/x/exp/mmap"
)

func main() {
	at, _ := mmap.Open("./tmp.txt")
	defer at.Close()
	buf := make([]byte, 1024)
	at.ReadAt(buf, 0)
	fmt.Println(string(buf))
}

mmap 除了减少一次数据拷贝外,还有一个优势在于,不同的虚拟内存地址可以指向同一个物理内存,这样多个进程之间就可以来共享这块数据。

在这里插入图片描述

2、sendfile

在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile()。

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

它的前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度。

该系统调用直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态。不管怎么说,文件内容是要先读到内核缓存中才能进行其他操作。

在这里插入图片描述

sendfile 的应用场景是:用户从磁盘读取一些文件数据后不需要经过任何计算与处理就通过网络传输出去。此场景的典型应用是消息队列。

3、sendfile + SG-DMA

linux2.4版本后,对sendfile做了优化升级,引入SG-DMA技术,其实就是对DMA拷贝加入了scatter-gather操作,它可以直接从内核空间缓冲区中将数据读取到网卡,这样的话还可以省去CPU拷贝。注意,SG-DMA技术只有网卡支持(通过命令ethtool -k eth0 | grep scatter-gather查看)。

在这里插入图片描述

可以发现sendfile + DMA scatter/gather实现的零拷贝发生了2次上下文切换以及2次数据拷贝,这就是真正的零拷贝技术,全程没有通过CPU来搬运数据,所有的数据都是通过DMA进行传输的。

三、Golang实现零拷贝

1、mmap
package main

import (
	"fmt"

	"golang.org/x/exp/mmap"
)

func main() {
	at, _ := mmap.Open("./tmp.txt")
	defer at.Close()
	buf := make([]byte, 1024)
	at.ReadAt(buf, 0)
	fmt.Println(string(buf))
}
2、sendfile

暂时没有找到Golang如何调用sendfile。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1870892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【NPS】哑终端设备如何实现域VLAN动态分配

在【NPS】微软NPS配置802.1x&#xff0c;验证域账号&#xff0c;动态分配VLAN&#xff08;有线网络续篇&#xff09;中&#xff0c;已经通过C3PL策略配置实现了802.1x验证没有通过时&#xff0c;自动分配一个Guest VLAN&#xff0c;以确保用户至少能够访问基本的网络服务。问题…

数字时代的文化革命:Facebook的社会影响

随着数字技术的飞速发展和互联网的普及&#xff0c;社交网络如今已成为人们日常生活中不可或缺的一部分。在众多社交平台中&#xff0c;Facebook作为最大的社交网络之一&#xff0c;不仅连接了全球数十亿用户&#xff0c;更深刻影响了人们的社会互动方式、文化认同和信息传播模…

展开说说:Android列表之RecyclerView

RecyclerView 它是从Android5.0出现的全新列表组件&#xff0c;更加强大和灵活。用于显示列表形式 (list) 或者网格形式 (grid) 的数据&#xff0c;替代ListView和GridView成为Android主流的列表组件。可以说Android客户端只要有表格的地方就有RecyclerView。 RecyclerView 内…

【linux】使用vnc连接远程桌面,需要安装tigervnc,并在服务端期待,然后在客户端使用tigervnc-viewer进行连接即可

vnc 远程设置方法 需要服务端安装软件&#xff1a; sudo apt install -y tigervnc-standalone-server# 先配置密码使用&#xff1a; tightvncpasswd启动服务&#xff0c;禁用本机 vncserver -localhost no -geometry 1924x1080 :1客户端安装软件&#xff1a; sudo apt insta…

JavaScript高级程序设计(第四版)--学习记录之基本引用类型

Date Date类型将日期保存为自协调世界时间1970年1月1日午夜至今所经过的毫秒数。 创建日期对象 let now new Date() Date.parse()方法接收一个表示日期的字符串参数&#xff0c;尝试将这个字符串转换为表示该日期的毫秒数。 let time new Date(Date.parse("May 24,2024&…

Jmeter+InfluxDB+Grafana性能测试数据展示

JmeterInfluxDBGrafana提供了一种更好的对Jmeter压测结果的实时监控展示。可以理解为数据源产生的数据加上时间记录并存储&#xff0c;然后使用各种开源图表组件进行展示。实现jmeter报告的更好的可视化展示 1&#xff09;方便测试结果数据落地以及更好的分析 2&#xff09;将…

超好用的思维导图—万兴亿图脑图 v10解锁版安装教程 (思维导图软件和头脑风暴工具)

前言 万兴亿图脑图 (Wondershare EdrawMind) 是一款多平台协作思维导图软件和头脑风暴工具,亿图思维导图提供丰富的布局,样式,主题及配色方案,集成拥有数万幅原创思维导图作品的思维导图社区,涵盖教育,职场,自我提升等各大领域精华知识.支持会议演示,多端创作,云端存储,导图分…

BioCLIP:物种图像的基础视觉模型

从无人机到个人手机&#xff0c;各种相机收集的自然世界图像是越来越丰富的生物信息来源。从图像中提取生物相关信息用于科学的计算方法和工具激增&#xff0c;尤其是计算机视觉。然而&#xff0c;其中大多数都是为特定任务设计的&#xff0c;不容易适应或扩展到新的问题、环境…

第30课 绘制原理图——放置网络标签

什么是网络标签&#xff1f; 我们在很多电路图中都能看到&#xff0c;为了让图纸更加简洁&#xff0c;并不是每一根导线都要确确实实地画出来。可以在导线悬空的一端添加一个名称标签&#xff0c;接着在另一根导线的悬空一端添加上一个同名的名称标签&#xff0c;那么就可以让…

1.回溯算法.基础

1.回溯算法 基础知识题目1.组合2.组合-优化3.组合总和|||4.电话号码和字母组合5.组合总和6.组合总和II7.分割回文串8.复原IP地址 基础知识 回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。回溯是递归的副产品&#xff0c;只要有递归就会有回溯 因为回溯的本质是穷…

【毛毛虫案例-重力 Objective-C语言】

一、接下来,我们给这个毛毛虫,添加一下重力 1.把我们之前的代码,复制粘贴一份儿,改个名字,叫做:17-毛毛虫案例-重力, 重力的话,实际上,就比较简单了啊,那我们重力的话,去添加的时候,我也要在外面,去添加, 重力的话,叫做啥,UIGravityBehavior,啊, UIGravity…

2024年度临沂市安全文化书画摄影展开幕

人海信息网山东讯 6月27日&#xff0c;2024年度临沂市安全文化书画摄影作品展&#xff0c;在临沂高新区隆重开幕。本次书画摄影展深入贯彻“以人为本&#xff0c;安全发展”的重要思想&#xff0c;立意高远&#xff0c;内涵丰富&#xff0c;思想深邃&#xff0c;承载着健康、幸…

【公开数据集获取】

Open Images Dataset https://www.youtube.com/watch?vdLSFX6Jq-F0

MySQL锁和使用

在MySQL中&#xff0c;锁用于控制并发访问&#xff0c;以保证数据的一致性和完整性。MySQL提供了多种类型的锁&#xff0c;包括表级锁、行级锁和页面级锁。以下是MySQL中各种锁的详细介绍及其使用方法&#xff1a; 1. 表级锁&#xff08;Table Locks&#xff09; 表级锁用于锁…

AI绘画Stable Diffusion 超强一键去除图片中的物体,免费使用!

大家好&#xff0c;我是设计师阿威 在生成图像时总有一些不完美的小瑕疵&#xff0c;比如多余的物体或碍眼的水印&#xff0c;它们破坏了图片的美感。但别担心&#xff0c;今天我们将介绍一款神奇的工具——sd-webui-cleaner&#xff0c;它可以帮助我们使用Stable Diffusion轻…

简易深度学习(1)深入分析神经元及多层感知机

一、神经元 单个神经元结构其实可以认为是一个线性回归模型。例如下图中 该神经元输入为三个特征&#xff08;x1&#xff0c;x2&#xff0c;x3&#xff09;&#xff0c;为了方便理解&#xff0c;大家可以认为每条线上都有一个权重和特征对应&#xff08;w1&#xff0c;w2&…

62.指针和二维数组(2)

一.指针和二维数组 1.如a是一个二维数组&#xff0c;则数组中的第i行可以看作是一个一维数组&#xff0c;这个一维数组的数组名是a[i]。 2.a[i]代表二维数组中第i行的首个元素的地址&#xff0c;即a[i][0]的地址。 二.进一步思考 二维数组可以看作是数组的数组&#xff0c;本…

算法入门:二分查找及其Java实现

在程序开发中&#xff0c;算法是解决问题的核心。本篇博客将详细讲解一种高效的查找算法——二分查找&#xff0c;并通过Java代码示例帮助你理解其实现和应用。 如果你觉得这篇文章对你有帮助&#xff0c;不要忘记点赞、收藏和关注我&#xff0c;这将是对我最大的支持和鼓励&am…

Vue.js中的虚拟DOM

一.节点和状态 在我们平常对DOM操作的时候,之前在vue没有诞生之前,以命令式的方式对DOM进行操作,页面上的每一个元素都可以看做成一个节点状态。 二.剔除和渲染 框架都有自己渲染的方式,假设一个页面的状态,随着Ajax请求的放松,状态发生改变,有以下的两种方式供你选择&#…

CVE-2024-37032漏洞预警:尽快升级Ollama

实时了解业内动态&#xff0c;论文是最好的桥梁&#xff0c;专栏精选论文重点解读热点论文&#xff0c;围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;…