Giter Site home page Giter Site logo

simpleclearfileio's Introduction

文件 I/O 简明概述

文件 I/O 性能是后台应用的主要瓶颈之一,一直以来想对文件 I/O 这个偌大的系统进行总结,故写此文。

文件 I/O 内容较多,书籍的意义在于能更系统地说明问题,避免博客文章散乱的问题。

书籍有涉及很大部分非原创内容,相关引用会在 REFERENCE 小节中指出。

书籍内容包括:

  • [1.page cache](1. page cache.html)
  • [2.DMA 与零拷贝技术](2. DMA 与零拷贝技术.html)
  • [3.mmap](3. mmap.html)
  • [4.文件分区](4. 文件分区.html)
  • [5.Java ByteBuffer与 Channel](5. Java ByteBuffer与 Channel.html)
  • [6.FileChannel](6. FileChannel.html)
  • [7.JavaVisual 工具](7. Visual VM.html)
  • [8.Java ByteBuffer 测试](8. Java ByteBuffer 测试.html)
  • [9.如何实现顺序读写](9. 如何实现顺序读写.html)

一些章节可能会需要一定的 Java 语言基础,其中:14 小节完全不需要 Java 基础,而 59 小节会涉及一定的 Java 代码。读者朋友可以有选择性地阅读。

linux_io_stack_diagram

Figure1.Linux IO Stack Diagram


其他

推荐阅读

  1. On Disk IO, Part 1: Flavors of IO
  2. On Disk IO, Part 2: More Flavours of IO
  3. Read, write & space amplification - pick 2

致谢

本书受到 文件 IO 操作的一些最佳实践 一文启发,很感谢阿里巴巴中间件团队的徐靖峰,其所写文章带来的启发意义非凡。

simpleclearfileio's People

Contributors

conwnet avatar wathenjiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

simpleclearfileio's Issues

mmap 代码补充

mmap 机制可以很大程度上简化磁盘文件操作,通过一定的封装,磁盘上的文件读写操作可以简化为内存的读写操作。
(1)直接读写内存-简洁明了

简单地读写内存非常简单,例如下面向数组的第三个元素进行赋值:

a := make([]int, 10)
a[0] = 511

内存中字段的读写操作相当自然,你甚至可能没有注意到在写内存这件事情。

(2)读写磁盘文件-步骤复杂

但是读写磁盘上的文件就相对复杂很多了,例如我们要在磁盘上读写的文件内容如下:

Hello World! This project is for learning mmap.

如果我们要读取文件开始 6 个偏移量后的 5 个字节数据,那么如下代码是一个方式:

package main

import (
	"fmt"
	"os"
)

func main() {
	f, _ := os.Open("./article.txt")
	defer f.Close()
	buffer := make([]byte, 5)
	f.Seek(6, 0)
	_, _ = f.Read(buffer)
  fmt.Println(string(buffer)) // 输出:world
}

读取磁盘上文件对比直接读取内存麻烦很多,步骤如下:

  • 打开文件,并且注意文件资源的及时释放
  • 创建一个 []byte 数组,用于存储从磁盘上读取的字节
  • 利用 Seek 方法设置文件读取的偏移量
  • 利用 Read 方法读取文件中的字节数据到 []byte 数组中

磁盘上文件读写比内存读写麻烦很多的原因就是 CPU 只能读写内存,而不能直接读写磁盘。磁盘文件上的字节数据需要首先读取到内存中,才能够被内存操作。

(3)mmap-读写磁盘文件就像读写内存

mmap 会负责将磁盘上不一定连续存储的数据按 block 读取到内核空间中,内核空间中的磁盘数据是连续的。然后,将内核空间中的数据映射到用户空间中,这个过程不涉及拷贝。

利用 mmap 机制,操作用户空间中的数据相当于操作磁盘上文件,它们之间的一致性依赖于缺页异常以及异步的 flush 机制实现。

案例代码如下:

package main

import (
	"fmt"
	"os"
	"syscall"
	"unsafe"
)

const defaultMaxFileSize = 1 << 30        // 假设文件最大为 1G
const defaultMemMapSize = 128 * (1 << 20) // 假设映射的内存大小为 128M

type Demo struct {
	file    *os.File                  // 文件
	data    *[defaultMaxFileSize]byte // 该数组负责指向 mmap 读取数据的 []byte 首地址
	dataRef []byte                    // 引用了 Mmmap 调用返回的 []byte 数组
}

// 根据 condition 状态位进行断言
func _assert(condition bool, msg string, v ...interface{}) {
	if !condition {
		panic(fmt.Sprintf(msg, v...))
	}
}

func (demo *Demo) mmap() {
	b, err := syscall.Mmap(int(demo.file.Fd()), 0, defaultMemMapSize, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	_assert(err == nil, "failed to mmap", err)
	demo.dataRef = b
	demo.data = (*[defaultMaxFileSize]byte)(unsafe.Pointer(&b[0]))
}

// grow 的作用是尝试将文件扩容至 size 大小,如果已经大于 size,那么不做任何操作
func (demo *Demo) grow(size int64) {
	if info, _ := demo.file.Stat(); info.Size() >= size {
		return
	}
	_assert(demo.file.Truncate(size) == nil, "failed to truncate")
}

// 资源释放
func (demo *Demo) munmap() {
	_assert(syscall.Munmap(demo.dataRef) == nil, "failed to munmap")
	demo.data = nil
	demo.dataRef = nil
}

func main() {
	_ = os.Remove("tmp.txt")
	// open file
	f, _ := os.OpenFile("tmp.txt", os.O_CREATE|os.O_RDWR, 0644) // 644 只有拥有者有读写权限;而属组用户和其他用户只有读权限
	demo := &Demo{file: f}
	demo.grow(1)
	// mmap
	demo.mmap()
	defer demo.munmap()
	// write into file on the disk like write into array in memory
	str := "helloworld"
	demo.grow(int64(len(str)))
	for i := 0; i < len(str); i++ {
		demo.data[i] = str[i]
	}
}

案例来源说明:Go Mmap 文件内存映射简明教程

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.