我已经编写了一个多goroutine版本的mergeSort,还编写了一个基准测试。现在,我想使用“去工具pprof”来分析代码的瓶颈。
当我获得cpu配置文件时,我在pprof中使用“ top10”来获得以下输出:
"folders": {
$userId: {
'depth_0': {
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': '',
'projectIds': [] // not all sub projectIds, only first level children
...
},
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': '',
'projectIds': [] // // not all sub projectIds, only first level children
...
},
},
'depth_1': {
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': 'id_amongst_depth_0',
'projectIds': [] // not all sub projectIds, only first level children
...
},
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': 'id_amongst_depth_0',
'projectIds': [] // not all sub projectIds, only first level children
...
},
},
'depth_2': {
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': 'id_amongst_depth_1',
'projectIds': [] // not all sub projectIds, only first level children
...
},
$auto_generated_folder_id_1: {
'name': 'first_project',
'parentId': 'id_amongst_depth_0',
'projectIds': [] // not all sub projectIds, only first level children
...
},
},
...
}
}
"projects": {
$userId: {
$auto_generated_project_id_1: {
'name': 'first_project',
'folderId': 'id_of_folder'
...
},
$auto_generated_project_id_2: {
'name': 'first_project',
'folderId': 'id_of_folder'
...
},
}
}
从上面,我认为好奇的瓶颈在sort.Merge中,因此我使用“列表合并”来深入研究该方法,并找到以下信息:
Showing nodes accounting for 4.73s, 98.54% of 4.80s total
Dropped 21 nodes (cum <= 0.02s)
Showing top 10 nodes out of 30
flat flat% sum% cum cum%
3.66s 76.25% 76.25% 3.66s 76.25% pingcap/talentplan/tidb/common/alg/sort.Merge
0.62s 12.92% 89.17% 0.64s 13.33% pingcap/talentplan/tidb/mergesort.prepare
0.17s 3.54% 92.71% 0.17s 3.54% runtime.freedefer
0.12s 2.50% 95.21% 0.14s 2.92% pingcap/talentplan/tidb/common/alg/sort.quickSort
0.10s 2.08% 97.29% 0.10s 2.08% runtime.memmove
0.03s 0.62% 97.92% 0.03s 0.62% runtime.memclrNoHeapPointers
0.03s 0.62% 98.54% 0.04s 0.83% runtime.stackpoolalloc
0 0% 98.54% 0.11s 2.29% pingcap/talentplan/tidb/common/alg/sort.MergeSortByMultiGoroutine
0 0% 98.54% 0.14s 2.92% pingcap/talentplan/tidb/common/alg/sort.QuickSort
0 0% 98.54% 4.04s 84.17% pingcap/talentplan/tidb/common/alg/sort.mergeSortByMultiGoroutine
让我困惑的是这里!在合并方法中,有4个for循环。第一个for循环和第4个for循环的比例大致相同,它们的任务都是将元素从一个切片移动到另一个切片。问题是,为什么第一个for-loop成本如此之高(1.58s加1.52s),而第四个for-loop成本却如此之少(仅为170ms)?这是违反直觉的!
该项目的github地址为https://github.com/Duncan15/talent-plan/tree/master/tidb/mergesort。您可以使用“ make pprof”运行基准测试并获取cpu配置文件和内存配置文件。
我想知道为什么会这样,如果有时间,请阅读我的代码并给我一些建议。
谢谢你告诉我!!
我编写了一些代码来验证当Merge方法在单goroutine环境中运行时,第一个for循环的成本与第四个for循环的成本大致相同,这似乎很直观。因此,我认为多goroutine环境是否会导致上述现象。但是在多goroutine环境中,Merge方法可以同时运行。换句话说,第1个for循环和第4个for循环同时运行,如果同时进行读写分片会增加成本,那么第4个for循环的成本也必须增加,但是从pprof输出中我们可以发现只有第一个for-loop的成本增加!
我还写了另一个测试来验证我的想法。您可以使用“ make vet”来运行它。此测试同时运行Merge方法。与多goroutine版本的mergeSort的不同之处在于,此测试没有有关排序的代码,而只是有关合并的代码。而且我惊讶地发现,在此测试中,第一个for循环的成本与第四个for循环的成本大致相同。所以最后我完全困惑了!