`
m635674608
  • 浏览: 5004982 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

分散/聚集 I/O(scatter-gather I/O)

 
阅读更多

概述

分散/聚集 I/O是一种可以在单次系统调用中对多个缓冲区输入输出的方法,可以把多个缓冲区的数据写到单个数据流,也可以把单个数据流读到多个缓冲区中。其命名的原 因在于数据会被分散到指定缓冲区向量,或者从指定缓冲区向量中聚集数据。这种输入输出方法也称为向量 I/O(vector I/O)。与之不同,标准读写系统调用(read,write)可以称为线性I/O(linear I/O)。

与线性 I/O 相比,分散/聚集 I/O 有如下几个优势:

编码模式更自然

如果数据本身是分段的(比如预定义的结构体的变量),向量 I/O 提供了直观的数据处理方式。

效率更高

单个向量 I/O 操作可以取代多个线性 I/O 操作。

性能更好

除了减少了发起的系统调用次数,通过内部优化,向量 I/O 可以比线性 I/O 提供更好的性能。

支持原子性

和多个线性 I/O 操作不同,一个进程可以执行单个向量 I/O 操作,避免了和其他进程交叉操作的风险。

readv() 和 writev()

Linux实现了POSIX 1003.1-2001中定义的一组实现分散/聚集 I/O机制的系统调用。该实现满足了上面所述的所有特性。

readv() 函数从文件描述符 fd 中读取 count 个段 (segment) (一个段即一个 iovec 结构体)到参数 iov 所指定的缓冲区中:

#include <sys/uio.h>

ssize_t readv (int fd,

                       const struct iovec *iov,

                       int count)

writev() 函数从参数 iov 指定的缓冲区中读取 count 个段的数据,并写入 fd 中:

#include <sys/uio.h>

ssize_t writev(int fd,

                       const struct iovec *iov,

                       int count)

 除了同时操作多个缓冲区外,readv() 函数和 writev() 函数的功能分别和 read(),write() 的功能一致。

每个 iovec 结构体描述一个独立的,物理不连续的缓冲区,我们称其为段(segment):

#include <sys/uio.h>

struct iovec {

       void      *iov_base;/* pointer to start of buffer */

       size_t   iov_len;/* size of buffer in bytes */

};

一组段的集合称为向量 (vector)。每个段描述了内存中所要读写的缓冲区的地址和长度。readv() 函数在处理下个缓冲区之前,会填满当前缓冲区的 iov_len 个字节。write() 函数在处理下个缓冲区之前,会把当前缓冲区所有 iov_len 个字节数据输出,这两个函数都会顺序处理向量中的段,从 iov[0] 开始,接着是 iov[1],一直到 iov[count - 1] 。

返回值

操作成功 时,readv() 函数和 write() 函数分别返回读写的字节数。该返回值应该等于所有 count 个 iov_len 的和。出错时,返回-1,并相应设置errno值。这些系统调用可能会返回任何 read() 和 write() 可能返回的错误,而且出错时,设置的 errno 值也与 read(), write() 相同。此外,标准还定义了另外两种错误场景。

 

第一种场景,由于返回值类型是 ssize_t , 如果所有 count 个iov_len 的和超出SSIZE_MAX, 则不会处理任何数据,返回-1,并把errno值设置为EINVAL。

 

第二种场景,POSIX 指出count值必须大于0,且小于等于IOV_MAX(IOV_MAX在文件<limits.h>定义。在Linux中,当前 IOV_MAX的值是1024。如果count为0,该系统调用会返回0。如果count大于IOV_MAX,不会处理任何数据,返回-1,并把 errno值设置为EINVAL。

 

优化count值

在向量 I/O 操作中,Linux内核必须分配内部数据结构来表示每个段(segment)。一般来说,是基于count的大小动态分配进行的。然而,为了优化,如果 count值足够小,内核会在栈上创建一个很小的段数组,通过避免动态分配段内存,从而获得性能上的一些提升。count 的阀值一般设置为8,,因此如果count值小于或等于8时,向量I/O操作会以一种高效的方式,在进程的内核栈中运行。

 

大多数情况下,无法选择在指定的向量I/O操作中一次同时传递多少个段。当你认为可以调试一个较小值时,选择8或更小的值肯定会得到性能的提升。

 

Linux内核把readv() 和writev() 作为系统调用实现,在内部使用分散/聚集 I/O模式。实际上,Linux内核中的所有I/O都是向量I/O,read() 和 write() 是作为向量 I/O来实现的,且向量中只有一个段。

 

例子

writev() 例子:

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <string.h>  
#include <sys/uio.h>  
  
int  main()  
{  
    struct iovec iov[3];  
    ssize_t nr;  
    int fd, i;  
  
    char *buf[] = {  
        "Just because you can do it, doesn't mean that you have to.\n",  
        "Just because you can do it, doesn't mean that you have to.\n",  
        "Just because you can do it, doesn't mean that you have to.\n" };  
  
    fd = open("c++.txt", O_WRONLY | O_CREAT | O_TRUNC);  
    if (fd == -1) {  
        perror("open");  
    }  
  
    /* fill out therr iovec structures */  
    for (i = 0; i < 3; ++i) {  
        iov[i].iov_base = buf[i];  
        iov[i].iov_len  = strlen(buf[i]) + 1;  
    }  
  
    /* write a single call, write them all out */  
    nr = writev(fd, iov, 3);  
    if (nr != -1) {  
        perror("writev");  
        return 1;  
    }  
  
    if (close(fd)) {  
        perror("close");  
    }  
  
    return 0;  
}  

 

readv() 例子:

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <sys/uio.h>  
  
int main()  
{  
    char foo[48], bar[50], baz[49];  
    struct iovec iov[3];  
    ssize_t nr;  
    int fd, i;  
  
    fd = open("c++.txt", O_RDONLY);  
    if (fd == -1) {  
        perror("open");  
        return 1;  
    }  
  
    /* set up our iovec structrues */  
    iov[0].iov_base = foo;  
    iov[0].iov_len = sizeof(foo);  
    iov[1].iov_base = bar;  
    iov[1].iov_len = sizeof(bar);  
    iov[2].iov_base = baz;  
    iov[2].iov_len = sizeof(baz);  
  
    /* read into the structures with a single call */  
    nr = readv(fd, iov, 3);  
    if (nr == -1) {  
        perror("readv");  
        return 1;  
    }  
  
    for (i = 0; i < 3; ++i) {  
        printf("%d: %s", i, (char*) iov[i].iov_base);  
    }  
  
    if (close(fd)) {  
        perror("close");  
        return 1;  
    }  
  
    return 0;  
} 
分享到:
评论

相关推荐

    NIO学习系列:缓冲区更多特性及分散/聚集IO

    本篇文章将深入探讨NIO中的缓冲区特性以及分散/聚集IO操作,这对于理解和优化Java程序的I/O性能至关重要。 缓冲区是NIO中处理数据的主要方式,它允许我们高效地读写数据。缓冲区在内存中分配一块区域,用于存储特定...

    torch_scatter-2.0.9-cp39-cp39-linux_x86_64whl.zip

    **torch_scatter** 是一个重要的PyTorch扩展库,它提供了一组操作,用于处理张量的分散(scatter)和聚集(gather)操作。这些操作在图神经网络(GNNs)、反向传播以及处理非连续数据时非常有用。torch_scatter库的...

    torch_scatter-2.0.5-cp37-cp37m-win_amd64whl.zip

    torch_scatter是一个针对PyTorch设计的库,它提供了一组操作,能够对张量进行散射(scatter)和聚集(gather)操作,这对于处理图神经网络(GNNs)和其他依赖非均匀数据结构的任务非常有用。例如,它可以用于计算图...

    torch_scatter-2.0.8-cp38-cp38-macosx_10_14_x86_64whl.zip

    `torch_scatter`是一个重要的Python库,它是针对PyTorch框架的一个扩展,主要功能是处理张量的分散(scatter)和聚集(gather)操作。在深度学习,尤其是图神经网络(GNNs)中,这些操作非常关键,因为它们允许在非...

    torch_scatter-2.0.8-cp38-cp38-win_amd64whl.zip

    在处理大规模数据时,某些操作如散列(scatter)和聚集(gather)是必不可少的。torch_scatter就是这样一个扩展库,它为PyTorch提供了对这些操作的支持。本文将详细介绍torch_scatter-2.0.8-cp38-cp38-win_amd64版本...

    torch_scatter-2.0.7-cp37-cp37m-linux_x86_64whl.zip

    首先,`torch_scatter`库的主要功能在于对张量执行类似“scatter”或“gather”的操作,这些操作在反向传播和计算图构建中尤为重要。例如,它可以将一个张量的值分散到另一个张量的特定索引上,或者将多个张量的值...

    torch_scatter-2.0.7-cp36-cp36m-linux_x86_64whl.zip

    `torch_scatter`是PyTorch的一个扩展库,主要提供了一组操作,用于处理张量的分散(scatter)和聚集(gather)运算。这些运算在神经网络,尤其是图神经网络(Graph Neural Networks, GNNs)中非常常见。例如,`...

    torch_scatter-2.0.5-cp37-cp37m-linux_x86_64whl.zip

    在PyTorch生态系统中,有一些扩展库如`torch_scatter`,它们提供了一些PyTorch原生不包含的特殊操作,如散射(scatter)和聚集(gather)运算。本文将深入探讨`torch_scatter`库,特别是针对标题中提及的`torch_...

    torch_scatter-2.0.9-cp36-cp36m-win_amd64whl.zip

    首先,torch_scatter模块的主要功能是提供对张量数据进行分散和聚集操作的支持。这些操作在图神经网络(GNNs)、注意力机制和损失函数中非常常见。例如,在图神经网络中,节点特征通常需要从其邻居节点处聚合信息,...

    torch_scatter-2.1.2-cp38-cp38-macosx_11_0_x86_64whl.zip

    首先,torch_scatter库主要包含了一系列张量的散射(scatter)和聚集(gather)操作,这些操作在神经网络中常用于反向传播、损失计算以及图神经网络等场景。例如,`scatter_add`函数可以将源张量的值分散并累加到...

    torch_scatter-2.0.5-cp38-cp38-win_amd64whl.zip

    首先,torch_scatter是一个针对PyTorch的扩展库,主要功能是提供对张量进行分散(scatter)和聚集(gather)操作的函数。这些操作在神经网络的反向传播、损失计算和优化过程中非常有用,特别是处理非填充(padding)...

    torch_scatter-2.0.6-cp37-cp37m-linux_x86_64whl.zip

    在PyTorch生态系统中,有一些辅助库如`torch_scatter`,它们扩展了PyTorch的基本功能,特别是在处理张量的分散(scatter)和聚集(gather)操作时。本文将深入探讨`torch_scatter`库以及其在`torch-1.7.0+cpu`版本中...

    torch_scatter-2.0.8-cp36-cp36m-win_amd64whl.zip

    例如,scatter操作可以将一个张量的元素分散到另一个张量的指定索引上,而gather则相反,它可以收集来自不同位置的数据并将其合并到一起。 在提供的压缩包中,"使用说明.txt"可能包含了关于如何安装和使用torch_...

    torch_scatter-2.0.9-cp37-cp37m-linux_x86_64whl.zip

    在进行复杂的神经网络运算时,常常需要对数据进行分散(scatter)和聚集(gather)操作,`torch_scatter`库就是为了应对这种需求而诞生的。标题提到的`torch_scatter-2.0.9-cp37-cp37m-linux_x86_64whl.zip`是一个...

    torch_scatter-2.0.5-cp38-cp38-linux_x86_64whl.zip

    首先,`torch_scatter`是一个针对PyTorch设计的库,它提供了张量的散射(scatter)和聚集(gather)操作,这些操作在处理非均匀数据、图神经网络和多对多的关系时非常有用。例如,散射操作可以将一个较大的张量分散...

    torch_scatter-2.0.7-cp37-cp37m-win_amd64whl.zip

    在处理大规模数据时,某些操作如聚集(scatter)和散射(gather)是必不可少的。`torch_scatter`是一个针对PyTorch的扩展库,它提供了这些操作的高效实现。本文将详细介绍`torch_scatter`模块的功能,并指导如何在...

    torch_scatter-2.0.7-cp36-cp36m-win_amd64whl.zip

    首先,torch_scatter库的核心功能是分散(scatter)和聚集(gather)操作。这些操作对于处理非局部的数据,比如在图神经网络中传播节点信息,或者在自注意力机制中计算权重,都是至关重要的。例如,scatter_add函数...

    torch_scatter-2.0.5-cp36-cp36m-macosx_10_9_x86_64whl.zip

    torch_scatter库的主要功能在于对张量进行分散(scatter)和聚集(gather)操作。这些操作在处理非标量化数据,尤其是图数据时非常关键。例如,它们可以用来将节点的属性值分散到它们的邻居上,或者从邻居那里收集...

    torch_scatter-2.1.1+pt20cpu-cp311-cp311-win_amd64whl.zip

    PyTorch是一个流行的深度学习框架,而torch_scatter是它的一个补充库,用于处理张量的分散(scatter)和聚集(gather)操作。这些操作在神经网络的反向传播、图神经网络以及任何需要将数据分发到不同位置或从不同...

Global site tag (gtag.js) - Google Analytics