测试go多协程并发写入内存和磁盘对性能的影响

最近希望能把一些过程,由传统的顺序执行改变成并发执行,看这样的优化是否能带来性能的提高。于是写了几个test来测试带来的影响。 测试的环境为mac pro,2.3 GHz Intel Core i5(双核),16GB内存。

(1)先测试并发写入内存是否能够得到性能的提高

测试代码如下:

func TestMemoryDB_SequenceExecute(t *testing.T) {
	db := New()
	t1 := time.Now()
	//如果是同一个key只会覆盖,无法测试出性能,因此需要是不同的key来测,写入同一个key需要的时间约等于不同key的一半时间
	//1千万次
	for i := 0; i < 10000000; i++ {
		err := db.Put([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"+strconv.Itoa(i)), []byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
		if err != nil {
			t.Fatalf("put failed: %v", err)
		}
	}
	t2 := time.Now()
	fmt.Println("spend time:", t2.Sub(t1)) //2.337S
}

func TestMemoryDB_ConcurrentExecute(t *testing.T) {
	db := New()
	wg := sync.WaitGroup{}
	wg.Add(2)
	t1 := time.Now()
	exec1 := func() {
		for i := 0; i < 5000000; i++ {
			err := db.Put([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"+strconv.Itoa(i)), []byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
			if err != nil {
				t.Fatalf("put failed: %v", err)
			}
		}
		wg.Done()
	}
	 exec2 := func() {
	 	for i := 2500000; i < 500000; i++ {
	 		err := db.Put([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"+string(i)), []byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
	 		if err != nil {
	 			t.Fatalf("put failed: %v", err)
	 		}
	 	}
	 	wg.Done()
	}

	go exec1()
	go exec2()
	wg.Wait()
	t2 := time.Now()
	fmt.Println("spend time:", t2.Sub(t1))
}

经测试顺序写入上述字符串1千万次,耗时13秒左右,开一个协程和开两个协程的耗时也是在14秒左右,如果开两个协程以上执行,耗时反而增多。因为越多协程,需要的调度和切换的时间会增多。

(2)再测试并发写入磁盘文件是否能够得到性能的提高

   因为磁盘的性能比内存的性能要低一个数量级别以上,因为只写入100万次刚才的字符串。

测试代码如下:

func TestFile_SequenceWrite(t *testing.T) {
	f, _ := os.Create("./output.txt")
	defer f.Close()
	t1 := time.Now()
	for i := 0; i < 2000000; i++ {
		_, err := f.Write([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
		if err != nil {
			t.Fatalf("put failed: %v", err)
		}
	}
	t2 := time.Now()
	fmt.Println("spend time:", t2.Sub(t1))
}

func TestFile_ConcurrentWrite(t *testing.T) {
	f1, _ := os.Create("./output1.txt")
	f2, _ := os.Create("./output2.txt")
	wg := sync.WaitGroup{}
	wg.Add(2)
	t1 := time.Now()
	go func() {
		for i := 0; i < 1000000; i++ {
			_, err := f1.Write([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
			if err != nil {
				t.Fatalf("put failed: %v", err)
			}
		}
		wg.Done()
	}()
	go func() {
		for i := 1000000; i < 2000000; i++ {
			_, err := f2.Write([]byte("0x6766c3279a7b32e52e89b24d203dd311aaf3019f9dd182f0128d8f12ab4490c2"))
			if err != nil {
				t.Fatalf("put failed: %v", err)
			}
		}
		wg.Done()
	}()
	wg.Wait()
	t2 := time.Now()
	fmt.Println("spend time:", t2.Sub(t1))
}

  经测试,写入一个66字节的字符串200万次 到一个文件里(约134.1MB),如果顺序执行,需要耗时12秒左右。但如果开两个协程并发写入两个不同的文件,耗时在8秒左右。如果开两个协程以上并发写入多个文件,不会再有性能的提高。当然,这个速度和固态硬盘的读写速度是差很远的,如果想提高写入速度,可以在内存里先构造出需要写入文件的内容,再写入,这样能极大提高写入速度。如果使用这种方式写入文件数据,以上述的环境只需要30-40µs即可写入完成。

猜你喜欢

转载自blog.csdn.net/kojhliang/article/details/83413896