Go 把一片分成N片
我正在尝试实现一个函数,该函数将TCP端口的一部分拆分为x个其他部分。这些切片将被发送给将扫描这些端口的工作者,因此x由工作者的数量设置 代码如下:Go 把一片分成N片,go,split,slice,Go,Split,Slice,我正在尝试实现一个函数,该函数将TCP端口的一部分拆分为x个其他部分。这些切片将被发送给将扫描这些端口的工作者,因此x由工作者的数量设置 代码如下: //createJobs将端口从指定协议扫描为相等的数目 //将返回的工作的数量。 func(t*Target)createJobs(原型字符串)([]jobMsg,错误){ //初始化作业片 作业:=[]作业消息{} //检查协议的一致性 如果u,确定:=t.portsToScan[proto];!确定{ 返回nil,fmt.Errorf(“当前
//createJobs将端口从指定协议扫描为相等的数目
//将返回的工作的数量。
func(t*Target)createJobs(原型字符串)([]jobMsg,错误){
//初始化作业片
作业:=[]作业消息{}
//检查协议的一致性
如果u,确定:=t.portsToScan[proto];!确定{
返回nil,fmt.Errorf(“当前协议列表中没有这样的协议%q”,proto)
}
//如果proto是ICMP,我们不需要扫描端口
如果proto==“icmp”{
return[]jobMsg{
jobMsg{ip:t.ip,协议:proto},
},零
}
步骤:=(len(t.portsToScan[proto])+t.workers-1)/t.workers
对于i:=0;i
下面是相应的单元测试:
func TestTarget_createJobs(t *testing.T) {
tests := []struct {
name string
pts map[string][]string
workersCount int
wantErr bool
}{
{
name: "5-1",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 1,
},
{
name: "5-2",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 2,
},
{
name: "5-3",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 3,
},
{
name: "5-4",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 4,
},
{
name: "5-5",
pts: map[string][]string{"tcp": []string{"1", "2", "3", "4", "5"}},
workersCount: 5,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tg := &Target{
portsToScan: tt.pts,
workers: tt.workersCount,
}
got, err := tg.createJobs("tcp")
if (err != nil) != tt.wantErr {
t.Errorf("Target.createJobs() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != tt.workersCount {
t.Errorf("Target.createJobs() = %d, wanted %d jobs; joblist %v", len(got), tt.workersCount, got)
}
})
}
}
func min(a, b int) int {
if a <= b {
return a
}
return b
}
初始端口列表保存在t.portsToScan[proto]
中,工作进程数(因此我要创建的片数)由t.workers
设置
最后,
len(jobs)
必须等于t.workers
,但我找不到如何做到这一点。您的算法使用step
作为批大小:
step := (len(t.portsToScan[proto]) + t.workers - 1) / t.workers
这不是最佳尺寸。例如,如果要扫描4个端口和3个工作进程,这将导致step=2
,这意味着您只有2个作业(2+2=4
)。但最好(更优化)有3个批次(尺寸2+1+1=4
)
所以批量的大小应该是
defSize := len(t.portsToScan[proto]) / t.workers
问题在于,如果长度不是t.workers的倍数,则最后的一些元素(端口)将不会分配给任何作业。对所有作业使用defSize+1
将太多
因此,最佳解决方案位于“中间”:一些作业将具有要扫描的defSize
端口,而一些作业将具有defSize+1
。必须有多少个defSize+1
?如果所有人都有defSize
,则丢失的数量为:
numBigger := len(t.portsToScan[proto]) - defSize*t.workers
请注意,如果要扫描的端口数少于worker,则上述计算会产生defSize=0
,因此一些worker将获得要扫描的0
端口,而一些worker将获得1
。这没关系,但不应该添加带有0
端口的作业进行扫描
使用此分发:
defSize := len(t.portsToScan[proto]) / t.workers
numBigger := len(t.portsToScan[proto]) - defSize*t.workers
size := defSize+1
for i, idx := 0, 0; i < t.workers; i++ {
if i == numBigger {
size--
if size == 0 {
break // 0 ports left to scan
}
}
jobs = append(jobs, jobMsg{
ip: t.ip,
protocol: proto,
ports: t.portsToScan[proto][idx : idx+size],
})
idx += size
}
defSize:=len(t.portsToScan[proto])/t.workers
numBigger:=len(t.portsToScan[proto])-defSize*t.workers
大小:=defSize+1
对于i,idx:=0,0;i
非常感谢您提供清晰完整的答案!遵循你的思维方式真的很有帮助!
defSize := len(t.portsToScan[proto]) / t.workers
numBigger := len(t.portsToScan[proto]) - defSize*t.workers
size := defSize+1
for i, idx := 0, 0; i < t.workers; i++ {
if i == numBigger {
size--
if size == 0 {
break // 0 ports left to scan
}
}
jobs = append(jobs, jobMsg{
ip: t.ip,
protocol: proto,
ports: t.portsToScan[proto][idx : idx+size],
})
idx += size
}