IO读写内幕关于io读写,分为两种:cacheio和directio。前者cacheio是目前最常用的io机制:它使用buffer缓冲区(内存中的一个地址)来防止频繁访问硬件,从而减少读写操作的时间消耗和硬件本身的消耗.Cacheio:基于操作系统将硬件与用户程序分离的思想,在实现时会在内核空间创建一个缓冲区。在读操作过程中,操作系统会将硬件中的数据读取到内核空间中的缓冲区中,用户进程会从内核空间中读取数据。buffer被复制到自己的用户空间(应用程序地址空间),如果后面再次读取,会在内核空间检查缓冲区,减少与硬件的io次数。同样,对于写操作,先将用户空间中的内容写入内核空间,应用程序无需等待,系统自动将内核空间缓冲区中的内容写入磁盘。tips:具体来说,在用户空间中,还指定了一块内存空间,用于存放从内核缓冲区读取的数据。我们也可以称之为用户空间的缓冲区。这样,用户应用程序就不需要在每次读写某些数据时都直接与内核空间通信。可以在用户空间的缓冲区中保存一段时间,这样可以减少用户空间和内核空间的通信次数,也就是减少系统调用的次数,在一定程度上减少开销。(不过一般没有明确规定,buffer指的是内核空间的缓冲区)优点:Cacheio使用操作系统内核缓冲区,一定程度上隔离了应用空间和实际物理设备,更安全.缓存io可以减少磁盘读取次数,从而提高性能。缺点:内核空间和用户空间之间频繁的数据拷贝也会对CPU和内存造成较大的开销。directio简介:directio就是在内核空间取消buffer缓冲区,数据直接从硬件传输到用户空间。这减少了从内核缓冲区到用户程序缓存的数据复制操作的开销。在数据库管理系统等典型应用场景中,它们往往会选择自己的缓存机制,因为数据库管理系统往往比操作系统更了解数据库中存储的数据,而数据库管理系统可以提供更有效的缓存机制。缓存机制,提高数据库中数据的访问性能。directio的缺点:如果访问的数据不在应用程序缓存中,每次都会直接从磁盘加载数据,这种直接加载会很缓存。通常directio与asynchronousio结合使用以获得更好的性能。(异步io:访问数据的线程发出请求后,线程会继续处理其他事情,而不是阻塞等待)以上只是对io机制的简单介绍。实际的io机制更复杂。可以参考以下文章了解更多:缓存io,directio,内存映射linux中directio机制介绍io读写原理pythonio读写io模块提供了Python处理各种问题的主要设施I/O类型。I/O主要分为三种类型:文本I/O、二进制I/O和原始I/O。这些是通用类别,每个类别都可以使用各种后备存储。属于任何这些类别的具体对象称为文件对象,其他常见术语是流或类文件对象。独立于其类别,每个具体的流对象也将具有不同的能力:它可以是只读的、只写的或读写的。所有流都会注意您提供给它们的数据类型。例如,将str对象提供给二进制流的write方法将引发TypeError。因此将字节对象提供给文本流的write()方法。对于文件对象,或者流,或者类文件对象,在io模块中定义了一些常用的接口,比如:read,readline,readlines,write,close,seek,tell,flush等打开函数open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)这里的buffering参数,指定的是内核空间的buffer大小,可以参考:pythonfilebufferio.open是内置函数的别名,open函数返回的是文件对象,或者说的streamabove,或类似文件的对象。所以对于open返回的对象,它也享有那些通用的接口。对应上面提到的cacheio机制,可以更深入的理解open函数背后做了什么。io.StringIOio.StringIO(initial_value='')使用内存中文本缓冲区的文本流。它继承了TextIOBase。文本缓冲区在调用close()方法时被丢弃。注意:该类是用于文本读写的,即不支持bytes类型数据的读写。对于bytes类型的数据,可以使用io.BytesIO(initial_bytes=None);还有一点就是不需要和硬件交互,所以可以推测缓冲区是在用户空间里面,而不是在内核空间。getvalue()返回包含缓冲区全部内容的str。注意:该方法不会改变streamposition的位置,相对于普通接口read。使用后,流位置会像指针一样跟着字符一个接一个地读取流到缓冲区的末尾。上面通用接口的read、readline、readlines、write、close就不用介绍了。这些是对文件对象,或者流,或者类文件对象的常用操作中非常常用的方法。这里简单介绍一下:seek、tell、flush这三个方法。seek(offset,whence=SEEK_SET)将流位置更改为给定的字节偏移量,从whence位置开始。whence值:SEEK_SET或0——流的开始(默认);偏移量应为零或正SEEK_CUR或1–当前流位置;offset可能是负数SEEK_END或2–流的结尾;offset通常为负tell()返回当前流的位置。提示:使用read、seek、tell,您可以使用流position.flush()如果适用,刷新流的写入缓冲区。这对只读和非阻塞流没有任何作用——因为之前使用此方法的StringIO是无效的。注意:该方法是将buffer中的内容flush到file对象对应的文件(硬件设备)中,但不会影响streamposition的位置。我们平时使用的close不仅仅是关闭buffer,它也是先flush,然后再关闭buffer。缓存概念的理解:将数据从不易访问的地方移到易访问的地方,减少重复读取所需的开销。将大于需要的数据读入一个中间区,然后需要额外的数据可以直接从中间区取出,无需再次从数据源读入。
