题目

假设有一个超长的切片,切片的元素类型为int,切片中的元素为乱序排列。限时5秒,使用多个goroutine查找切片中是否存在给定值,在找到目标值或者超时后立刻结束所有goroutine的执行。

比如切片为:[23, 32, 78, 43, 76, 65, 345, 762, …… 915, 86],查找的目标值为345,如果切片中存在目标值程序输出:”Found it!”并且立即取消仍在执行查找任务的goroutine。如果在超时时间未找到目标值程序输出:”Timeout! Not Found”,同时立即取消仍在执行查找任务的goroutine

思路

思路参考:上周并发题的解题思路以及介绍Go语言调度器

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main

import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)

func main() {
targetNum := 898982
total := 2000000000
s := GetRandomSlice(total, 200000000, targetNum)
t := time.Now()
manager := NewManager(250000000)
manager.Search(s, targetNum)
fmt.Println(manager.Result())
fmt.Printf("find the number of %d, time conumin %v\n", total, time.Since(t))
}

func GetRandomSlice(sliceLen int, randNum int, targetNum int) []int {
tmp := make([]int, sliceLen)
rand.Seed(time.Now().UnixNano())
for i := 0; i < sliceLen; i++ {
randNum := rand.Intn(randNum)
tmp[i] = randNum
if randNum == targetNum {
fmt.Println("randNum is ", i)
}
}
return tmp
}

type Manager struct {
s []int
targetNum int
chunkSize int
chunkNum int
once sync.Once
ctx context.Context
cancel func()
result chan string
}

func NewManager(chunkSize int) *Manager {
ctx, cancel := context.WithCancel(context.Background())
return &Manager{
chunkSize: chunkSize,
once: sync.Once{},
ctx: ctx,
cancel: cancel,
result: make(chan string),
}
}

func (m *Manager) Search(s []int, target int) {
m.s = s
m.targetNum = target
Chunk(len(s), m.chunkSize, m.Worker)
}

func Chunk(total, chunkSize int, f func(part, startIndex, endIndex int)) {
if total%chunkSize == 0 {
for i := 0; i < total/chunkSize; i++ {
e := (i + 1) * chunkSize
f(i+1, i*chunkSize, e)
}
} else {
for i := 0; i <= total/chunkSize; i++ {
e := (i + 1) * chunkSize
if i == (total / chunkSize) {
e = i*chunkSize + total%chunkSize
}
f(i+1, i*chunkSize, e)
}
}
}

func (m *Manager) Worker(part, startIndex, endIndex int) {
m.chunkNum++
go func() {
for i, v := range m.s[startIndex:endIndex] {
if v == m.targetNum {
m.result <- fmt.Sprintf("Found! At index %d\n", (part-1)*m.chunkSize+i)
return
}
select {
case <-m.ctx.Done():
return
default:
continue
}
}
m.result <- ""
return
}()
}

func (m *Manager) Result() string {
var once sync.Once
var num int
for {
select {
case <-time.After(time.Second * time.Duration(10)):
once.Do(m.cancel)
return "Timeout! Not Found"
case res := <-m.result:
if res != "" {
once.Do(m.cancel)
return res
}
num++
if num == m.chunkNum {
once.Do(m.cancel)
return "All Task Done,Not Found!"
}
}
}
}

参考