Performance golang中的磁盘写入性能
在下面的代码中,我使用golang中的bufio将消息写入文件。我的磁盘I/O速度大约为1000M/s。奇怪的是,当写入文件的大小小于20G时,写入速度约为每秒800M~900M,略低于I/O速度。但是,当文件大小超过21G时,我发现写入速度约为每秒200M,远低于I/O速度。我不知道为什么,有人能帮我吗?多谢各位Performance golang中的磁盘写入性能,performance,file,go,io,fwrite,Performance,File,Go,Io,Fwrite,在下面的代码中,我使用golang中的bufio将消息写入文件。我的磁盘I/O速度大约为1000M/s。奇怪的是,当写入文件的大小小于20G时,写入速度约为每秒800M~900M,略低于I/O速度。但是,当文件大小超过21G时,我发现写入速度约为每秒200M,远低于I/O速度。我不知道为什么,有人能帮我吗?多谢各位 package main import "fmt" import ( "os" "time" "flag" "bufio" ) func main
package main
import "fmt"
import (
"os"
"time"
"flag"
"bufio"
)
func main() {
var pRound = flag.Int64("round", 3500000, "loop round")
flag.Parse()
var message string
for i := 0; i < 1024; i++ {
message += "1234567890"
}
message += "\n"
f, err := os.OpenFile("server", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
fmt.Println(err)
return
}
w := bufio.NewWriter(f)
var i int64 = 0
round := *pRound
start := time.Now()
for i = 0; i < round; i++ {
w.WriteString(message)
}
w.Flush()
f.Close()
end := time.Now()
nanoseconds := end.Sub(start).Nanoseconds()
speed := 1000000000 * round / nanoseconds
fmt.Printf("round: %v\n", round)
fmt.Printf("Nanoseconds: %v\n", nanoseconds)
fmt.Printf("speed: %v\n", speed)
}
以下是我的C代码:
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <sys/uio.h>
#include <time.h>
#include <sys/time.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cout << "usage: " << argv[0] << " round" << std::endl;
return -1;
}
int round = atoi(argv[1]);
int fd = open("file.data", O_CREAT | O_APPEND | O_RDWR, 0666);
if (fd == -1) {
std::cout << "open file error: " << strerror(errno) << std::endl;
return -1;
}
struct iovec vec[IOV_MAX];
int len = 1024;
for (int i = 0; i < IOV_MAX; i++) {
vec[i].iov_base = new char[len];
vec[i].iov_len = len;
char *buf = NULL;
for (int j = 0; j < len - 1; j++) {
buf = (char*)vec[i].iov_base;
buf[j] = j % 10 + '1';
}
buf[len - 1] = '\n';
}
timeval tv1;
gettimeofday(&tv1, NULL);
for (int i = 0; i < round; i++) {
writev(fd, vec, IOV_MAX);
}
close(fd);
timeval tv2;
gettimeofday(&tv2, NULL);
for (int i = 0; i < IOV_MAX; i++) {
char* buf = (char*)vec[i].iov_base;
delete[] buf;
}
std::cout << "seconds: " << tv2.tv_sec - tv1.tv_sec << std::endl;
std::cout << "milliseconds: " << tv2.tv_usec - tv1.tv_usec << std::endl;
int64_t total = int64_t(len) * IOV_MAX * round;
float t = (tv2.tv_sec - tv1.tv_sec) * 1000000.0 + (tv2.tv_usec - tv1.tv_usec);
float speed = 1000000.0 * total / t / 1024 / 1024;
std::cout << "total: " << total << " Bytes" << std::endl;
std::cout << "total: " << total / 1024.0 / 1024.0 << " M" << std::endl;
std::cout << "total: " << total / 1024.0 / 1024.0 / 1024.0 << " G" << std::endl;
std::cout << "speed: " << speed << " M/s" << std::endl;
return 0;
}
diskio.go来自哪里
我想我得到了答案,测试结果是由磁盘缓冲区原因造成的。我使用hdparm
command测试了我的磁盘速度,得到了以下结果:
hdparm -Tt /dev/sde1
/dev/sde1:
Timing cached reads: 18166 MB in 2.00 seconds = 9093.93 MB/sec
Timing buffered disk reads: 584 MB in 3.01 seconds = 194.18 MB/sec
所以,当文件大小小于18166M时,我的程序可能正在将字节写入缓冲区。此后,程序将写入磁盘,因此速度较慢。您的问题无法再现。你的代码有错误 我们预计磁盘写入时间会受到许多因素的影响:程序、其他程序、操作系统、硬件等等 启动一台独立的专用机器,然后运行
diskio.go
程序。你得到了什么结果?例如,在我的机器上:
$ go build diskio.go
$ time ./diskio -size=32
written: 34359738368B 154333936544ns 34.36GB 154.33s 222.63MB/s
real 2m35.323s
user 0m6.418s
sys 0m41.994s
$ time ./diskio -size=16
written: 17179869184B 77901269159ns 17.18GB 77.90s 220.53MB/s
real 1m18.746s
user 0m2.849s
sys 0m21.721s
$ time ./diskio -size=8
written: 8589934592B 38940248134ns 8.59GB 38.94s 220.59MB/s
real 0m39.625s
user 0m1.719s
sys 0m12.493s
$ time ./diskio -size=1
written: 1073741824B 4738082404ns 1.07GB 4.74s 226.62MB/s
real 0m4.851s
user 0m0.069s
sys 0m0.755s
$
正如预期的那样,花在程序上的时间很少,花在操作系统上的时间更多,花在等待磁盘上的时间更多。写入速度没有急剧变化
diskio.go
:
package main
import (
"bufio"
"flag"
"fmt"
"os"
"time"
)
func writeFile(fSize int64) error {
fName := `/home/peter/diskio` // test file
defer os.Remove(fName)
f, err := os.Create(fName)
if err != nil {
return err
}
const defaultBufSize = 4096
buf := make([]byte, defaultBufSize)
buf[len(buf)-1] = '\n'
w := bufio.NewWriterSize(f, len(buf))
start := time.Now()
written := int64(0)
for i := int64(0); i < fSize; i += int64(len(buf)) {
nn, err := w.Write(buf)
written += int64(nn)
if err != nil {
return err
}
}
err = w.Flush()
if err != nil {
return err
}
err = f.Sync()
if err != nil {
return err
}
since := time.Since(start)
err = f.Close()
if err != nil {
return err
}
fmt.Printf("written: %dB %dns %.2fGB %.2fs %.2fMB/s\n",
written, since,
float64(written)/1000000000, float64(since)/float64(time.Second),
(float64(written)/1000000)/(float64(since)/float64(time.Second)),
)
return nil
}
var size = flag.Int("size", 8, "file size in GiB")
func main() {
flag.Parse()
fSize := int64(*size) * (1024 * 1024 * 1024)
err := writeFile(fSize)
if err != nil {
fmt.Fprintln(os.Stderr, fSize, err)
}
}
主程序包
进口(
“布菲奥”
“旗帜”
“fmt”
“操作系统”
“时间”
)
func writeFile(fSize int64)错误{
fName:=`/home/peter/diskio`//测试文件
延迟操作系统删除(fName)
f、 错误:=os.Create(fName)
如果错误!=零{
返回错误
}
const defaultBufSize=4096
buf:=生成([]字节,默认BUFSIZE)
buf[len(buf)-1]='\n'
w:=bufio.NewWriterSize(f,len(buf))
开始:=时间。现在()
写入:=int64(0)
对于i:=int64(0);i
操场:我想我知道这个问题的答案了。因为我的磁盘I/O速度约为194M/s,磁盘缓冲区I/O速度约为9093M/s。但磁盘缓冲区大小约为18166M。因此,当文件大小小于20G时,写入速度更快。我使用此命令测试磁盘I/O速度:
hdparm -Tt /dev/sde1
/dev/sde1:
Timing cached reads: 18166 MB in 2.00 seconds = 9093.93 MB/sec
Timing buffered disk reads: 584 MB in 3.01 seconds = 194.18 MB/sec
读取“2.00秒18166 MB”。这不是缓存的大小。可能有一些磁盘具有巨大的缓存,但在三位数MB范围内的缓存更多。可能是因为此时磁盘缓冲区已饱和?几个月前,我用C语言编写了一个类似的过程,使用
writev
方法。我发现写入速度几乎等于磁盘I/O速度。这是否可以证明它与磁盘缓冲区无关?请分析您的代码,这是您最大的希望。如果性能下降超过21G,您应该在配置文件中看到一些内容。很可能是io等待。我的磁盘I/O速度约为1000M/s。不是那么简单。您的IO操作有多大?是否存在在IO操作之间移动任何物理磁盘头的寻道操作?我向您保证,如果您在物理旋转磁盘驱动器上的随机位置执行512字节IO操作,您将不会看到接近“大约1000M/s”的IO速率。在消费级SATA磁盘上,您可能会看到IO速率降低到20 KB/秒甚至更低。我知道多个线程同时写入同一磁盘是一个缓慢的操作。因为磁盘头查找位置花费了很多时间。所以我选择了一个干净的磁盘进行测试。没有其他数据,也没有正在运行的程序读取或写入磁盘。我试图在这里注释代码,但我不知道如何操作。所以我在我的问题上再次上传了我的测试结果。我想我的速度测试出了问题。谢谢,谢谢。我想我已经得到了答案。
package main
import (
"bufio"
"flag"
"fmt"
"os"
"time"
)
func writeFile(fSize int64) error {
fName := `/home/peter/diskio` // test file
defer os.Remove(fName)
f, err := os.Create(fName)
if err != nil {
return err
}
const defaultBufSize = 4096
buf := make([]byte, defaultBufSize)
buf[len(buf)-1] = '\n'
w := bufio.NewWriterSize(f, len(buf))
start := time.Now()
written := int64(0)
for i := int64(0); i < fSize; i += int64(len(buf)) {
nn, err := w.Write(buf)
written += int64(nn)
if err != nil {
return err
}
}
err = w.Flush()
if err != nil {
return err
}
err = f.Sync()
if err != nil {
return err
}
since := time.Since(start)
err = f.Close()
if err != nil {
return err
}
fmt.Printf("written: %dB %dns %.2fGB %.2fs %.2fMB/s\n",
written, since,
float64(written)/1000000000, float64(since)/float64(time.Second),
(float64(written)/1000000)/(float64(since)/float64(time.Second)),
)
return nil
}
var size = flag.Int("size", 8, "file size in GiB")
func main() {
flag.Parse()
fSize := int64(*size) * (1024 * 1024 * 1024)
err := writeFile(fSize)
if err != nil {
fmt.Fprintln(os.Stderr, fSize, err)
}
}
hdparm -Tt /dev/sde1
/dev/sde1:
Timing cached reads: 18166 MB in 2.00 seconds = 9093.93 MB/sec
Timing buffered disk reads: 584 MB in 3.01 seconds = 194.18 MB/sec