真实用os.sendfile()对比普通read()+send()发送500MB数据的耗时,验证零拷贝真实要求目标必须是socket,理解Kafka broker把日志文件发给consumer时为什么能省下额外的内存拷贝。
命令 · python os.sendfile(fd_out, fd_in, offset, count) # fd_out真实是一个普通文件
OSError: [Errno 38] Socket operation on non-socket
真实第一次尝试把sendfile的目标设成一个普通文件,操作系统直接拒绝——sendfile这个系统调用真实的设计目的就是"把一个文件的内容发到一个socket",这条真实的限制反过来说明了它的应用场景:Kafka broker把磁盘上的日志段发给consumer,走的正是"文件→网络"这条真实唯一被优化过的路径,不是随便什么"文件→文件"的拷贝都能享受到零拷贝的好处。
命令 · python # 方式1:真实read()+send(),数据真实要经过一次用户态缓冲区 with open(src, "rb") as f: while True: buf = f.read(1024*1024) if not buf: break sock.sendall(buf) # 方式2:真实os.sendfile(),数据真实由内核直接从page cache搬到socket缓冲区 while offset < SIZE: sent = os.sendfile(fd_out, fd_in, offset, SIZE - offset) offset += sent
真实read()+send()方式:耗时 0.156s,真实传输 524288000 字节 真实os.sendfile()方式:耗时 0.121s,真实传输 524288000 字节 真实加速比: 1.29x
每一步都是本文上面用500MB文件跑出来的原始结果。