问题描述:
我这里准备用go对一个数据量在百万左右的slice进行去重处理,我目前的思路是如下代码:
RemoveDuplicate函数为普通的单线程去重函数。
RemoveDuplicateMultiThread为多线程去重函数,在RemoveDuplicateMultiThread中,我把需要去重的切片list按照CPU核心数量(我的电脑是双核四线程,所以我写死在代码中为4)平均切分,然后依次发射4个goroutine,参数带上之前切分好的四个slice,goroutine中分别对这4个slice进行去重,然后再把结果发送到channel上,最后RemoveDuplicateMultiThread里面channel把所有结果获取完之后再合并。
但是我这个思路只能在重复数据很小,并且要求不是非常严谨的情况下才有用,如果切割之后的四个切片里面互相有重复数据,还是无法实现去重,感觉这算法有点问题,谁能帮忙看看怎么改进一下啊
而且我在实际测试的时候发现CPU占用率最高为75%而不是100%,这是为什么呢?Windows任务管理器里面看到该go进程的线程数为6,这能说明什么呢?
操作系统:Windows 7 64bit,CPU:i5-4210M,8G内存
func RemoveDuplicate(list []string, ret chan []string) {
var x []string = []string{}
for _, i := range list {
if len(x) == 0 {
x = append(x, i)
} else {
for k, v := range x {
if i == v {
break
}
if k == len(x)-1 {
x = append(x, i)
}
}
}
}
//return x
ret <- x
}
func RemoveDuplicateMultiThread(list []string) (ret []string) {
listQueue := make(chan []string)
var listList [4][]string
listLen := len(list)
sliceLen := int(listLen / 4)
lastSliceLen := listLen % 4
var start, end int
for i := 0; i < 4-1; i++ {
start = i * sliceLen
end = (i + 1) * sliceLen
listList[i] = list[start:end]
}
listList[4-1] = list[:lastSliceLen]
for i := 0; i < 4-1; i++ {
go RemoveDuplicate(listList[i], listQueue)
}
ret = <-listQueue
ret = append(ret, ret...)
return ret
}
第 1 个答案:
可以使用空间换时间的方式,多定义一个map来判断元素是否重复
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
arr := gen()
fmt.Println(len(arr))
resArr := removeDuplicate(arr)
fmt.Println(len(resArr))
}
// 模拟生成一百万随机数
func gen() []int {
start := time.Now()
arr := make([]int, 1000000)
s := rand.NewSource(time.Now().UnixNano() + rand.Int63n(9999))
r := rand.New(s)
for i := 0; i < 1000000; i++ {
arr[i] = r.Intn(1000000)
}
fmt.Println("gen time:", fmt.Sprintf("%vms", (time.Now().UnixNano()-start.UnixNano())/1e+6))
return arr
}
// 去重
func removeDuplicate(arr []int) []int {
start := time.Now()
resArr := make([]int, 0)
tmpMap := make(map[int]interface{})
for _, val := range arr {
if _, ok := tmpMap[val]; !ok {
resArr = append(resArr, val)
tmpMap[val] = struct{}{}
}
}
fmt.Println("removeDuplicate time:", fmt.Sprintf("%vms", (time.Now().UnixNano()-start.UnixNano())/1e+6))
return resArr
}
如果使用多线程方式,需要注意map的不安全问题。
后台controller的封装格式如下:@RequestMapping(value = "/getUserInfo", method = { RequestMethod.POST, Reque ...